From 1659bf4ce62c8f6f7050f04c771995e1676d51a5 Mon Sep 17 00:00:00 2001 From: schlangster Date: Wed, 30 Jul 2014 14:03:43 +0200 Subject: [PATCH 01/75] Continuation target domain defaults to source. --- include/react/Domain.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/react/Domain.h b/include/react/Domain.h index 1279c3f9..7fb1ef16 100644 --- a/include/react/Domain.h +++ b/include/react/Domain.h @@ -145,7 +145,7 @@ class TransactionStatus template < typename D, - typename D2 + typename D2 = D > class Continuation : public REACT_IMPL::ContinuationBase { From 6c297aa67a443f8c3db1966f35789702a1932d52 Mon Sep 17 00:00:00 2001 From: schlangster Date: Wed, 30 Jul 2014 14:04:17 +0200 Subject: [PATCH 02/75] Cleaned up LifeSim benchmark a bit (it's still not great). --- benchmarks/src/BenchmarkLifeSim.h | 63 ++++++++++++++++++------------- 1 file changed, 36 insertions(+), 27 deletions(-) diff --git a/benchmarks/src/BenchmarkLifeSim.h b/benchmarks/src/BenchmarkLifeSim.h index b53856dd..1ebab386 100644 --- a/benchmarks/src/BenchmarkLifeSim.h +++ b/benchmarks/src/BenchmarkLifeSim.h @@ -67,6 +67,8 @@ class Time template class Region { + Time& theTime; + public: USING_REACTIVE_DOMAIN(D) @@ -83,21 +85,17 @@ class Region SignalT FoodPerDay = MakeSignal( theTime.Season, - [] (int season) { - return season == summer ? 20 : 10; - }); + calculateFoodPerDay); SignalT FoodOutputPerDay = MakeSignal( With(FoodPerDay,AnimalCount), - [] (int food, int count) { - return count > 0 ? food/count : 0; - }); + calculateFoodOutputPerDay); EventsT FoodOutput = Pulse(theTime.NewDay, FoodOutputPerDay); Region(Time& time, int x, int y) : - Bounds( x*10, x*10+9, y*10, y*10+9 ), - theTime( time ) + theTime( time ), + Bounds( x*10, x*10+9, y*10, y*10+9 ) {} PositionT Center() const @@ -126,7 +124,16 @@ class Region } private: - Time& theTime; + static int calculateFoodPerDay(int season) + { + return season == summer ? 20 : 10; + } + + static int calculateFoodOutputPerDay(int food, int count) + { + return count > 0 ? food/count : 0; + } + }; /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -138,7 +145,7 @@ class World public: USING_REACTIVE_DOMAIN(D) - vector>> Regions; + vector>> Regions; World(Time& time, int w) : w_( w ) @@ -199,14 +206,7 @@ class Animal EventsT*> RegionChanged = Monitor(NewRegion); SignalT Age = Iterate(theTime.NewDay, 0, Incrementer()); - - SignalT Health = Iterate( - FoodReceived, - 100, - [] (int food, int health) { - auto newHealth = health + food - 10; - return newHealth < 0 ? 0 : newHealth > 10000 ? 10000 : newHealth; - }); + SignalT Health = Iterate(FoodReceived, 100, calculateHealth); Animal(Time& time, World& world, Region* initRegion, unsigned seed) : theTime( time ), @@ -239,20 +239,29 @@ class Animal [this] (PositionT pos) { return theWorld.GetRegion(pos); }) + ), + regionChangeContinuation_ + ( + MakeContinuation(RegionChanged, With(CurrentRegion), + [this] (Region* newRegion, Region* oldRegion) { + oldRegion->EnterOrLeave(leave); + newRegion->EnterOrLeave(enter); + + // Change region in continuation + CurrentRegion <<= newRegion; + }) ) { initRegion->EnterOrLeave(enter); + } - Observe( - RegionChanged, - With(CurrentRegion), - [this] (Region* newRegion, Region* oldRegion) { - oldRegion->EnterOrLeave(leave); - newRegion->EnterOrLeave(enter); +private: + Continuation regionChangeContinuation_; - // Change region in continuation - CurrentRegion <<= newRegion; - }); + static int calculateHealth(int food, int health) + { + auto newHealth = health + food - 10; + return newHealth < 0 ? 0 : newHealth > 10000 ? 10000 : newHealth; } }; From 2c77bd7add90d688188ee4961f55d2893b899d52 Mon Sep 17 00:00:00 2001 From: schlangster Date: Wed, 30 Jul 2014 16:02:32 +0200 Subject: [PATCH 03/75] Examples cleanup. --- examples/src/BasicSynchronization.cpp | 68 ++++++++- examples/src/Main.cpp | 195 +------------------------- 2 files changed, 69 insertions(+), 194 deletions(-) diff --git a/examples/src/BasicSynchronization.cpp b/examples/src/BasicSynchronization.cpp index 38f05f3e..2e49be40 100644 --- a/examples/src/BasicSynchronization.cpp +++ b/examples/src/BasicSynchronization.cpp @@ -9,6 +9,7 @@ #include "tbb/tick_count.h" #include "react/Domain.h" +#include "react/Signal.h" #include "react/Event.h" #include "react/Observer.h" @@ -37,7 +38,7 @@ namespace example1 Sensor mySensor; Observe(mySensor.Samples, [] (int v) { - cout << v << std::endl; + cout << v << endl; }); TransactionStatus status; @@ -157,14 +158,79 @@ namespace example2 } } +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// Example 3 - Continuations (1) +/////////////////////////////////////////////////////////////////////////////////////////////////// +namespace example3 +{ + using namespace react; + using namespace std; + + REACTIVE_DOMAIN(D, sequential_concurrent) + + class Widget + { + public: + USING_REACTIVE_DOMAIN(D) + + VarSignalT Label1 = MakeVar(string( "Change" ));; + VarSignalT Label2 = MakeVar(string( "me!" ));; + + EventSourceT<> Reset = MakeEventSource(); + + Widget() : + resetCont_ + ( + MakeContinuation( + Reset, + [this] (Token) { + Label1 <<= string( "Change" ); + Label2 <<= string( "me!" ); + }) + ) + {} + + private: + Continuation resetCont_; + }; + + void Run() + { + cout << "Example 3 - Continuations (1)" << endl; + + Widget myWidget; + int sum = 0; + + Observe(myWidget.Label1, [&] (const string& v) { + cout << "Label 1 changed to " << v << endl;; + }); + + Observe(myWidget.Label2, [&] (const string& v) { + cout << "Label 2 changed to " << v << endl;; + }); + + myWidget.Label1 <<= "Hello"; + myWidget.Label2 <<= "world"; + + cout << "Resetting..." << endl; + + myWidget.Reset(); + + cout << endl; + } +} + /////////////////////////////////////////////////////////////////////////////////////////////////// /// Run examples /////////////////////////////////////////////////////////////////////////////////////////////////// int main() { example1::Run(); + example2::v1::Run(); example2::v2::Run(); + example3::Run(); + return 0; } \ No newline at end of file diff --git a/examples/src/Main.cpp b/examples/src/Main.cpp index 1a8f1ee3..89f61f07 100644 --- a/examples/src/Main.cpp +++ b/examples/src/Main.cpp @@ -18,205 +18,14 @@ 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. - - -void SignalExample3() -{ - REACTIVE_DOMAIN(D, sequential_concurrent) - - cout << "Signal Example 3" << endl; - - auto src = MakeVar(0); - - // Input values can be manipulated imperatively in observers. - // Inputs are implicitly thread-safe, buffered and executed in a continuation turn. - // This continuation turn is queued just like a regular turn. - // If other turns are already queued, they are executed before the continuation. - auto cont = MakeContinuation(src, [&] (int v) { - cout << "V: " << v << endl; - if (v < 10) - src <<= v+1; - }); - - src <<= 1; - - cout << endl; -} - -void SignalExample4() -{ - REACTIVE_DOMAIN(L, sequential_concurrent, ToposortEngine) - REACTIVE_DOMAIN(R, sequential_concurrent, ToposortEngine) - - cout << "Signal Example 4" << endl; - - auto srcL = MakeVar(0); - auto srcR = MakeVar(0); - - auto contL = MakeContinuation(srcL, [&] (int v) { - cout << "L->R: " << v << endl; - if (v < 10) - srcR <<= v+1; - }); - - auto contR = MakeContinuation(srcR, [&] (int v) { - cout << "R->L: " << v << endl; - if (v < 10) - srcL <<= v+1; - }); - - srcL <<= 1; - printf("End\n"); - - cout << endl; -} - -void SignalExample5() -{ - REACTIVE_DOMAIN(L, sequential_concurrent, ToposortEngine) - REACTIVE_DOMAIN(R, sequential_concurrent, ToposortEngine) - - cout << "Signal Example 5" << endl; - - auto srcL = MakeVar(0); - auto depL1 = MakeVar(0); - auto depL2 = MakeVar(0); - auto srcR = MakeVar(0); - - auto contL = MakeContinuation( - Monitor(srcL), - With(depL1, depL2), - [&] (int v, int depL1, int depL2) { - cout << "L->R: " << v << endl; - if (v < 10) - srcR <<= v+1; - }); - - auto contR = MakeContinuation( - Monitor(srcR), - [&] (int v) { - cout << "R->L: " << v << endl; - if (v < 10) - srcL <<= v+1; - }); - - srcL <<= 1; - printf("End\n"); - - cout << endl; -} - void testme() { - REACTIVE_DOMAIN(D, sequential_concurrent) - - std::vector results; - - auto f_0 = [] (int a) -> int - { - int k = 0; - for (int i = 0; i<10000; i++) - k += i; - return a + k; - }; - - auto f_n = [] (int a, int b) -> int - { - int k = 0; - for (int i=0; i<10000; i++) - k += i; - return a + b + k; - }; - - auto n1 = MakeVar(0); - auto n2 = n1 ->* f_0; - auto n3 = ((n2, n1) ->* f_n) ->* f_0; - auto n4 = n3 ->* f_0; - auto n5 = ((((n4, n3) ->* f_n), n1) ->* f_n) ->* f_0; - auto n6 = n5 ->* f_0; - auto n7 = ((n6, n5) ->* f_n) ->* f_0; - auto n8 = n7 ->* f_0; - auto n9 = ((((((n8, n7) ->* f_n), n5) ->* f_n), n1) ->* f_n) ->* f_0; - auto n10 = n9 ->* f_0; - auto n11 = ((n10, n9) ->* f_n) ->* f_0; - auto n12 = n11 ->* f_0; - auto n13 = ((((n12, n11) ->* f_n), n9) ->* f_n) ->* f_0; - auto n14 = n13 ->* f_0; - auto n15 = ((n14, n13) ->* f_n) ->* f_0; - auto n16 = n15 ->* f_0; - auto n17 = ((((((n16, n15) ->* f_n), n13) ->* f_n), n9) ->* f_n) ->* f_0; - - auto src = MakeEventSource(); - - atomic c( 0 ); - - Observe(src, [&] (int v){ - c++; - }); - - auto x0 = tbb::tick_count::now(); - - TransactionStatus st; - - for (int i=0; i<10000; i++) - { - AsyncTransaction(st, [&,i] { - n1 <<= 1+i; - }); - } - - for (int i=0; i<10000; i++) - { - AsyncTransaction(st, [&,i] { - n1 <<= 20000+i; - }); - } - - for (int i=0; i<10000; i++) - { - AsyncTransaction(st, [&,i] { - n1 <<= 100000+i; - }); - } - - st.Wait(); - - //std::thread t3([&] { - // for (int i=0; i<10000; i++) - // n1 <<= 1+i; - //}); - - //std::thread t2([&] { - // for (int i=0; i<10000; i++) - // n1 <<= 20000+i; - //}); - - //std::thread t1([&] { - // for (int i=0; i<10000; i++) - // n1 <<= 100000+i; - //}); - - //t3.join(); - //t2.join(); - //t1.join(); - //std::chrono::milliseconds dura( 10000 ); - //std::this_thread::sleep_for( dura ); - - auto x1 = tbb::tick_count::now(); - - double d = (x1 - x0).seconds(); - printf("Time %g\n", d); - printf("Updates %d\n", c.load()); - printf("n1 %d\n", n1()); + // Note: This project exists as a sandbox where I occasionally stage new examples. + // Currently it's empty. } int main() { - SignalExample3(); - SignalExample4(); testme(); #ifdef REACT_ENABLE_LOGGING From 7ab678dbb7fc8526412d2efd09c08c40bec81314 Mon Sep 17 00:00:00 2001 From: schlangster Date: Wed, 30 Jul 2014 16:02:42 +0200 Subject: [PATCH 04/75] Readme tweak. --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index a10f27b3..7285d7f1 100644 --- a/README.md +++ b/README.md @@ -156,7 +156,6 @@ VarSignalT a = MakeVar(1); VarSignalT b = MakeVar(2); VarSignalT c = MakeVar(3); -// Using overloaded arithmetic operators instead of MakeSignal SignalT x = (a + b) * c; ``` From 318b585cc9d04b23827f354178e6cfb60eaa6d44 Mon Sep 17 00:00:00 2001 From: schlangster Date: Wed, 30 Jul 2014 16:28:39 +0200 Subject: [PATCH 05/75] Example cleanup. --- examples/src/BasicSynchronization.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/examples/src/BasicSynchronization.cpp b/examples/src/BasicSynchronization.cpp index 2e49be40..ec2be1c9 100644 --- a/examples/src/BasicSynchronization.cpp +++ b/examples/src/BasicSynchronization.cpp @@ -173,10 +173,10 @@ namespace example3 public: USING_REACTIVE_DOMAIN(D) - VarSignalT Label1 = MakeVar(string( "Change" ));; - VarSignalT Label2 = MakeVar(string( "me!" ));; + VarSignalT Label1 = MakeVar(string( "Change" )); + VarSignalT Label2 = MakeVar(string( "me!" )); - EventSourceT<> Reset = MakeEventSource(); + EventSourceT<> Reset = MakeEventSource(); Widget() : resetCont_ @@ -199,14 +199,13 @@ namespace example3 cout << "Example 3 - Continuations (1)" << endl; Widget myWidget; - int sum = 0; Observe(myWidget.Label1, [&] (const string& v) { - cout << "Label 1 changed to " << v << endl;; + cout << "Label 1 changed to " << v << endl; }); Observe(myWidget.Label2, [&] (const string& v) { - cout << "Label 2 changed to " << v << endl;; + cout << "Label 2 changed to " << v << endl; }); myWidget.Label1 <<= "Hello"; From 31856896ddbc4e64d2b10f60100969d4a52578ea Mon Sep 17 00:00:00 2001 From: schlangster Date: Fri, 1 Aug 2014 19:17:11 +0200 Subject: [PATCH 06/75] Changed Subystem to Console for Release profile in some examples. --- project/msvc/Example_BasicAlgorithms.vcxproj | 1 + project/msvc/Example_BasicComposition.vcxproj | 1 + project/msvc/Example_BasicEvents.vcxproj | 1 + project/msvc/Example_BasicObservers.vcxproj | 1 + project/msvc/Example_BasicReactors.vcxproj | 1 + project/msvc/Example_BasicSignals.vcxproj | 1 + 6 files changed, 6 insertions(+) diff --git a/project/msvc/Example_BasicAlgorithms.vcxproj b/project/msvc/Example_BasicAlgorithms.vcxproj index cd4b6e9b..eeffca5a 100644 --- a/project/msvc/Example_BasicAlgorithms.vcxproj +++ b/project/msvc/Example_BasicAlgorithms.vcxproj @@ -118,6 +118,7 @@ true true true + Console diff --git a/project/msvc/Example_BasicComposition.vcxproj b/project/msvc/Example_BasicComposition.vcxproj index 8b336087..01d26c88 100644 --- a/project/msvc/Example_BasicComposition.vcxproj +++ b/project/msvc/Example_BasicComposition.vcxproj @@ -118,6 +118,7 @@ true true true + Console diff --git a/project/msvc/Example_BasicEvents.vcxproj b/project/msvc/Example_BasicEvents.vcxproj index 2e3bad5e..d5d13295 100644 --- a/project/msvc/Example_BasicEvents.vcxproj +++ b/project/msvc/Example_BasicEvents.vcxproj @@ -118,6 +118,7 @@ true true true + Console diff --git a/project/msvc/Example_BasicObservers.vcxproj b/project/msvc/Example_BasicObservers.vcxproj index f99889bf..9fa37b8c 100644 --- a/project/msvc/Example_BasicObservers.vcxproj +++ b/project/msvc/Example_BasicObservers.vcxproj @@ -118,6 +118,7 @@ true true true + Console diff --git a/project/msvc/Example_BasicReactors.vcxproj b/project/msvc/Example_BasicReactors.vcxproj index f05f8265..07701d98 100644 --- a/project/msvc/Example_BasicReactors.vcxproj +++ b/project/msvc/Example_BasicReactors.vcxproj @@ -118,6 +118,7 @@ true true true + Console diff --git a/project/msvc/Example_BasicSignals.vcxproj b/project/msvc/Example_BasicSignals.vcxproj index 653861ba..e090dd8a 100644 --- a/project/msvc/Example_BasicSignals.vcxproj +++ b/project/msvc/Example_BasicSignals.vcxproj @@ -118,6 +118,7 @@ true true true + Console From 32724f98565730f61df79a9ddf1ade97f6e21080 Mon Sep 17 00:00:00 2001 From: schlangster Date: Fri, 1 Aug 2014 19:20:23 +0200 Subject: [PATCH 07/75] Fixed #2. --- examples/src/BasicAlgorithms.cpp | 35 ++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/examples/src/BasicAlgorithms.cpp b/examples/src/BasicAlgorithms.cpp index 07907c76..22f92cfb 100644 --- a/examples/src/BasicAlgorithms.cpp +++ b/examples/src/BasicAlgorithms.cpp @@ -93,7 +93,7 @@ namespace example2 } /////////////////////////////////////////////////////////////////////////////////////////////////// -/// Example 3 - Creating stateful signals (1) +/// Example 3 - Folding event streams into signals (1) /////////////////////////////////////////////////////////////////////////////////////////////////// namespace example3 { @@ -119,7 +119,7 @@ namespace example3 void Run() { - cout << "Example 3 - Creating stateful signals (1)" << endl; + cout << "Example 3 - Folding event streams into signals (1)" << endl; Counter myCounter; @@ -135,7 +135,7 @@ namespace example3 } /////////////////////////////////////////////////////////////////////////////////////////////////// -/// Example 4 - Creating stateful signals (2) +/// Example 4 - Folding event streams into signals (2) /////////////////////////////////////////////////////////////////////////////////////////////////// namespace example4 { @@ -149,23 +149,36 @@ namespace example4 public: USING_REACTIVE_DOMAIN(D) - EventSourceT Input = MakeEventSource(); + EventSourceT Input = MakeEventSource(); - SignalT Average = Iterate( + SignalT Count = Iterate( + Tokenize(Input), + 0, + [] (Token, int oldCount) { + return oldCount + 1; + }); + + SignalT Sum = Iterate( Input, 0.0f, - [] (int sample, float oldAvg) { - return (oldAvg + sample) / 2.0f; + [] (float v, float sum) { + return v + sum; + }); + + SignalT Average = MakeSignal( + With(Sum,Count), + [] (float sum, int count) { + return count != 0 ? sum / count : 0.0f; }); }; void Run() { - cout << "Example 4 - Creating stateful signals (2)" << endl; + cout << "Example 4 - Folding event streams into signals (2)" << endl; Sensor mySensor; - mySensor.Input << 10 << 5 << 10 << 8; + mySensor.Input << 10.0f << 5.0f << 10.0f << 8.0f; cout << "Average: " << mySensor.Average() << endl; // output: 3 @@ -174,7 +187,7 @@ namespace example4 } /////////////////////////////////////////////////////////////////////////////////////////////////// -/// Example 5 - Creating stateful signals (3) +/// Example 5 - Folding event streams into signals (3) /////////////////////////////////////////////////////////////////////////////////////////////////// namespace example5 { @@ -210,7 +223,7 @@ namespace example5 void Run() { - cout << "Example 5 - Creating stateful signals (3)" << endl; + cout << "Example 5 - Folding event streams into signals (3)" << endl; Counter myCounter; From ccd5f37f9be70ca041ad26b332ca6825b0ad097c Mon Sep 17 00:00:00 2001 From: schlangster Date: Fri, 1 Aug 2014 21:08:18 +0200 Subject: [PATCH 08/75] Comment correction. --- examples/src/BasicAlgorithms.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/src/BasicAlgorithms.cpp b/examples/src/BasicAlgorithms.cpp index 22f92cfb..69229ee5 100644 --- a/examples/src/BasicAlgorithms.cpp +++ b/examples/src/BasicAlgorithms.cpp @@ -180,7 +180,7 @@ namespace example4 mySensor.Input << 10.0f << 5.0f << 10.0f << 8.0f; - cout << "Average: " << mySensor.Average() << endl; // output: 3 + cout << "Average: " << mySensor.Average() << endl; // output: 8.25 cout << endl; } From 4850a6a83456823901a8f4bdbbd411252fb731a1 Mon Sep 17 00:00:00 2001 From: schlangster Date: Sat, 2 Aug 2014 17:30:16 +0200 Subject: [PATCH 09/75] Updated readme. --- README.md | 53 ++++++++++++++++++----------------------------------- 1 file changed, 18 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index 7285d7f1..957014de 100644 --- a/README.md +++ b/README.md @@ -3,12 +3,12 @@ C++React is reactive programming library for C++11. Generally speaking, it provides abstractions to handle change propagation and data processing for a push-based event model. -A more practical description is that it enables coordinated, multi-layered - and potentially parallel - execution of callbacks. +A more practical description is that it enables coordinated, multi-layered - _and potentially parallel_ - execution of callbacks. All this happens implicitly, based on declarative definitions, with guarantees regarding - _update minimality_ - nothing is re-calculated or processed unnecessarily; - _glitch freedom_ - no transiently inconsistent data sets; -- _thread safety_ - no data races for parallel execution. +- _thread safety_ - no data races for parallel execution by avoiding side effects. The core abstractions of the library are @@ -30,19 +30,17 @@ Additional features include [If you're interested in learning about C++React, have a look at its documentation.](http://schlangster.github.io/cpp.react/) -## Development +## Using the library -This library is a work-in-progress and should not be considered release quality yet. +This library is a work-in-progress. It should not be considered release quality yet and its API might still change. It is, however, in a perfectly usable state and has already received a fair amount of testing and tuning. - ### Dependencies * [Intel TBB 4.2](https://www.threadingbuildingblocks.org/) (required) * [Google test framework](https://code.google.com/p/googletest/) (optional, to compile the unit tests) * [Boost 1.55.0 C++ Libraries](http://www.boost.org/) (optional, to include Reactor.h, which requires `boost::coroutine`) - ### Compiling C++React has been tested with the following compilers: @@ -69,20 +67,21 @@ For more details, refer to the [Build instructions](https://github.com/schlangst ### Signals Signals are self-updating reactive variables. -They can be combined as expressions to create new signals, which are automatically re-calculated whenever one of their dependencies changes. +They can be combined in expressions to create new signals, which are automatically re-calculated when their dependencies change. ```C++ using namespace std; using namespace react; -// Define a reactive domain that uses single-threaded, sequential updating +// Defines a reactive domain that uses single-threaded, sequential updating REACTIVE_DOMAIN(D, sequential) -// Define aliases for types of the given domain, +// Defines aliases for types of the given domain, // e.g. using VarSignalT = VarSignal USING_REACTIVE_DOMAIN(D) // Two reactive variables that can be manipulated imperatively +// to input external changes VarSignalT width = MakeVar(1); VarSignalT height = MakeVar(2); @@ -110,7 +109,7 @@ Observe(area, [] (int newValue) { }); ``` -Overloaded operators for signal types allow to omit `MakeSignal` in this case for a more concise syntax: +Overloaded operators for signal types allow to omit `MakeSignal` for a more concise syntax: ```C++ // Lift as reactive expression - equivalent to previous example SignalT area = width * height; @@ -118,7 +117,8 @@ SignalT area = width * height; ### Event streams -Event streams represent flows of discrete values. They are first-class objects and can be merged, filtered, transformed or composed to more complex types: +Unlike signals, event streams are not centered on changing state, but represent flows of discrete values. +They are first-class objects and can be merged, filtered, transformed or composed to more complex types: ```C++ using namespace std; @@ -128,39 +128,27 @@ REACTIVE_DOMAIN(D, sequential) USING_REACTIVE_DOMAIN(D) // Two event sources -EventSourceT leftClicked = MakeEventSource(); -EventSourceT rightClicked = MakeEventSource(); +EventSourceT leftClick = MakeEventSource(); +EventSourceT rightClick = MakeEventSource(); // Merge both event streams -EventsT merged = leftClicked | rightClicked; +EventsT anyClick = leftClick | rightClick; // React to events -Observe(merged, [] (Token) { +Observe(anyClick, [] (Token) { cout << "clicked!" << endl; }); ``` ``` -rightClicked.Emit(); // => clicked! +leftClick.Emit(); // => clicked! +rightClick.Emit(); // => clicked! ``` ### Parallelism and concurrency -The change propagation is handled implicitly. -Depending on the selected concurrency policy, updates can be parallelized: - -```C++ -// Sequential updating -REACTIVE_DOMAIN(D, sequential) - -VarSignalT a = MakeVar(1); -VarSignalT b = MakeVar(2); -VarSignalT c = MakeVar(3); - -SignalT x = (a + b) * c; -``` +When enabling it through the concurrency policy, updates are automatically parallelized: ```C++ -// Parallel updating REACTIVE_DOMAIN(D, parallel) VarSignalT in = MakeVar(0); @@ -181,11 +169,6 @@ SignalT op2 = MakeSignal(in, [] (int in) SignalT out = op1 + op2; ``` -### More examples - -* [Examples](https://github.com/schlangster/cpp.react/tree/master/examples/src) -* [Test cases](https://github.com/schlangster/cpp.react/tree/master/tests/src) - ## Acknowledgements The API of C++React has been inspired by the following two research papers: From 3b1b6bc3963893a2ed07e31383bf9cfccb84b585 Mon Sep 17 00:00:00 2001 From: schlangster Date: Sun, 3 Aug 2014 19:12:38 +0200 Subject: [PATCH 10/75] Fixed #3. --- README.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 957014de..5c27b6bc 100644 --- a/README.md +++ b/README.md @@ -153,17 +153,17 @@ REACTIVE_DOMAIN(D, parallel) VarSignalT in = MakeVar(0); -SignalT op1 = MakeSignal(in, [] (int in) -{ - int result = doCostlyOperation1(in); - return result; -}; - -SignalT op2 = MakeSignal(in, [] (int in) -{ - int result = doCostlyOperation2(in); - return result; -}; +SignalT op1 = MakeSignal(in, + [] (int in) { + int result = doCostlyOperation1(in); + return result; + }); + +SignalT op2 = MakeSignal(in, + [] (int in) { + int result = doCostlyOperation2(in); + return result; + }); // op1 and op2 can be re-calculated in parallel SignalT out = op1 + op2; From 7b6009eea952cf8b3d1894218ede6a2d2eb7a76b Mon Sep 17 00:00:00 2001 From: schlangster Date: Thu, 7 Aug 2014 02:29:40 +0200 Subject: [PATCH 11/75] Misc additions to Util.h. --- include/react/common/Util.h | 77 +++++++++++++++++++++++++++++++------ 1 file changed, 65 insertions(+), 12 deletions(-) diff --git a/include/react/common/Util.h b/include/react/common/Util.h index 35e8e771..b50c005b 100644 --- a/include/react/common/Util.h +++ b/include/react/common/Util.h @@ -102,18 +102,29 @@ struct Identity /////////////////////////////////////////////////////////////////////////////////////////////////// struct DontMove {}; +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// DisableIfSame +/////////////////////////////////////////////////////////////////////////////////////////////////// +template +struct DisableIfSame : + std::enable_if::type, + typename std::decay::type>::value> {}; + /////////////////////////////////////////////////////////////////////////////////////////////////// /// AddDummyArgWrapper /////////////////////////////////////////////////////////////////////////////////////////////////// template struct AddDummyArgWrapper { - // Dummy int to make sure it calls the right ctor - template - AddDummyArgWrapper(int, FIn&& func) : MyFunc( std::forward(func) ) {} - AddDummyArgWrapper(const AddDummyArgWrapper& other) = default; - AddDummyArgWrapper(AddDummyArgWrapper&& other) : MyFunc( std::move(other.MyFunc) ) {} + + AddDummyArgWrapper(AddDummyArgWrapper&& other) : + MyFunc( std::move(other.MyFunc) ) + {} + + template ::type> + explicit AddDummyArgWrapper(FIn&& func) : MyFunc( std::forward(func) ) {} TRet operator()(TArg, TDepValues& ... args) { @@ -126,12 +137,15 @@ struct AddDummyArgWrapper template struct AddDummyArgWrapper { - // Dummy int to make sure it calls the right ctor - template - AddDummyArgWrapper(int, FIn&& func) : MyFunc( std::forward(func) ) {} - +public: AddDummyArgWrapper(const AddDummyArgWrapper& other) = default; - AddDummyArgWrapper(AddDummyArgWrapper&& other) : MyFunc( std::move(other.MyFunc) ) {} + + AddDummyArgWrapper(AddDummyArgWrapper&& other) : + MyFunc( std::move(other.MyFunc) ) + {} + + template ::type> + explicit AddDummyArgWrapper(FIn&& func) : MyFunc( std::forward(func) ) {} void operator()(TArg, TDepValues& ... args) { @@ -152,8 +166,20 @@ template > struct AddDefaultReturnValueWrapper { - template - AddDefaultReturnValueWrapper(FIn&& func) : MyFunc( std::forward(func) ) {} + AddDefaultReturnValueWrapper(const AddDefaultReturnValueWrapper&) = default; + + AddDefaultReturnValueWrapper(AddDefaultReturnValueWrapper&& other) : + MyFunc( std::move(other.MyFunc) ) + {} + + template + < + typename FIn, + class = typename DisableIfSame::type + > + explicit AddDefaultReturnValueWrapper(FIn&& func) : + MyFunc( std::forward(func) ) + {} template TRet operator()(TArgs&& ... args) @@ -165,6 +191,33 @@ struct AddDefaultReturnValueWrapper F MyFunc; }; +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// IsCallableWith +/////////////////////////////////////////////////////////////////////////////////////////////////// +template +< + typename F, + typename TRet, + typename ... TArgs +> +class IsCallableWith +{ +private: + using NoT = char[1]; + using YesT = char[2]; + + template + static YesT& check( + decltype( static_cast( + (std::declval())(std::declval() ...))) *); + + template + static NoT& check(...); + +public: + enum { value = sizeof(check(nullptr)) == sizeof(YesT) }; +}; + /****************************************/ REACT_IMPL_END /***************************************/ // Expand args by wrapping them in a dummy function From 12d72a5d4978aba346ee0961a02c25fa15479d00 Mon Sep 17 00:00:00 2001 From: schlangster Date: Thu, 7 Aug 2014 02:47:50 +0200 Subject: [PATCH 12/75] Added a new range-based signature option for event callbacks. Instead of passing a function `func(E)` that is called for every event on the stream, EventRange allows to iterate them manually. This allows client code to add node-level parallelization with parallel_for or parallel_reduce. It's supported by existing Observe and MakeContinuation, and also by a new operation `Process`, which is a more generic form of Transform/Filter. The signature of process callbacks is `void(EventRange range, EventInserter out)`. out is a back_insert_iterator. --- include/react/Domain.h | 26 ++- include/react/Event.h | 66 ++++++ include/react/Observer.h | 60 +++-- .../react/detail/graph/ContinuationNodes.h | 45 +++- include/react/detail/graph/EventNodes.h | 217 +++++++++++++++--- include/react/detail/graph/GraphBase.h | 24 ++ include/react/detail/graph/ObserverNodes.h | 74 +++--- 7 files changed, 415 insertions(+), 97 deletions(-) diff --git a/include/react/Domain.h b/include/react/Domain.h index 7fb1ef16..ac049438 100644 --- a/include/react/Domain.h +++ b/include/react/Domain.h @@ -235,10 +235,21 @@ auto MakeContinuation(TransactionFlagsT flags, const Events& trigger, FIn&& "MakeContinuation requires support for concurrent input to target domain."); using REACT_IMPL::EventContinuationNode; + using REACT_IMPL::AddContinuationRangeWrapper; + using REACT_IMPL::IsCallableWith; + using REACT_IMPL::EventRange; + using F = typename std::decay::type; + using WrapperT = + typename std::conditional< + IsCallableWith>::value, + F, + AddContinuationRangeWrapper + >::type; + return Continuation( - std::make_shared>( + std::make_shared>( flags, GetNodePtr(trigger), std::forward(func))); } @@ -274,8 +285,19 @@ auto MakeContinuation(TransactionFlagsT flags, const Events& trigger, "MakeContinuation requires support for concurrent input to target domain."); using REACT_IMPL::SyncedContinuationNode; + using REACT_IMPL::AddContinuationRangeWrapper; + using REACT_IMPL::IsCallableWith; + using REACT_IMPL::EventRange; + using F = typename std::decay::type; + using WrapperT = + typename std::conditional< + IsCallableWith, TDepValues ...>::value, + F, + AddContinuationRangeWrapper + >::type; + struct NodeBuilder_ { NodeBuilder_(TransactionFlagsT flags, const Events& trigger, FIn&& func) : @@ -288,7 +310,7 @@ auto MakeContinuation(TransactionFlagsT flags, const Events& trigger, -> Continuation { return Continuation( - std::make_shared>( + std::make_shared>( MyFlags, GetNodePtr(MyTrigger), std::forward(MyFunc), GetNodePtr(deps) ...)); diff --git a/include/react/Event.h b/include/react/Event.h index 550ef5ac..e3f70f3e 100644 --- a/include/react/Event.h +++ b/include/react/Event.h @@ -345,6 +345,72 @@ auto Transform(const Events& source, const SignalPack& d depPack.Data); } +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// Process +/////////////////////////////////////////////////////////////////////////////////////////////////// +using REACT_IMPL::EventRange; +using REACT_IMPL::EventInserter; + +template +< + typename TOut, + typename D, + typename TIn, + typename FIn, + typename F = typename std::decay::type +> +auto Process(const Events& src, FIn&& func) + -> Events +{ + using REACT_IMPL::EventProcessingNode; + + return Events( + std::make_shared>( + GetNodePtr(src), std::forward(func))); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// Process - Synced +/////////////////////////////////////////////////////////////////////////////////////////////////// +template +< + typename TOut, + typename D, + typename TIn, + typename FIn, + typename ... TDepValues +> +auto Process(const Events& source, const SignalPack& depPack, FIn&& func) + -> Events +{ + using REACT_IMPL::SyncedEventProcessingNode; + + using F = typename std::decay::type; + + struct NodeBuilder_ + { + NodeBuilder_(const Events& source, FIn&& func) : + MySource( source ), + MyFunc( std::forward(func) ) + {} + + auto operator()(const Signal& ... deps) + -> Events + { + return Events( + std::make_shared>( + GetNodePtr(MySource), std::forward(MyFunc), GetNodePtr(deps) ...)); + } + + const Events& MySource; + FIn MyFunc; + }; + + return REACT_IMPL::apply( + NodeBuilder_( source, std::forward(func) ), + depPack.Data); +} + /////////////////////////////////////////////////////////////////////////////////////////////////// /// Flatten /////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/include/react/Observer.h b/include/react/Observer.h index 07d76c32..9b50fc6a 100644 --- a/include/react/Observer.h +++ b/include/react/Observer.h @@ -185,7 +185,6 @@ auto Observe(const Signal& subject, FIn&& func) SignalObserverNode >::type; - const auto& subjectPtr = GetNodePtr(subject); std::unique_ptr> nodePtr( new TNode(subjectPtr, std::forward(func)) ); @@ -212,18 +211,29 @@ auto Observe(const Events& subject, FIn&& func) using REACT_IMPL::ObserverNode; using REACT_IMPL::EventObserverNode; using REACT_IMPL::AddDefaultReturnValueWrapper; + using REACT_IMPL::AddObserverRangeWrapper; + using REACT_IMPL::IsCallableWith; + using REACT_IMPL::EventRange; using F = typename std::decay::type; - using R = typename std::result_of::type; - using WrapperT = AddDefaultReturnValueWrapper; - // If return value of passed function is void, add ObserverAction::next as - // default return value. - using TNode = typename std::conditional< - std::is_same::value, - EventObserverNode, - EventObserverNode - >::type; + using WrapperT = + typename std::conditional< + IsCallableWith>::value, + F, + typename std::conditional< + IsCallableWith::value, + AddObserverRangeWrapper, + typename std::conditional< + IsCallableWith>::value, + AddDefaultReturnValueWrapper, + AddObserverRangeWrapper> + >::type + >::type + >::type; + + using TNode = EventObserverNode; const auto& subjectPtr = GetNodePtr(subject); @@ -253,18 +263,30 @@ auto Observe(const Events& subject, using REACT_IMPL::ObserverNode; using REACT_IMPL::SyncedObserverNode; using REACT_IMPL::AddDefaultReturnValueWrapper; + using REACT_IMPL::AddObserverRangeWrapper; + using REACT_IMPL::IsCallableWith; + using REACT_IMPL::EventRange; using F = typename std::decay::type; - using R = typename std::result_of::type; - using WrapperT = AddDefaultReturnValueWrapper; - // If return value of passed function is void, add ObserverAction::next as - // default return value. - using TNode = typename std::conditional< - std::is_same::value, - SyncedObserverNode, - SyncedObserverNode - >::type; + using WrapperT = + typename std::conditional< + IsCallableWith, TDepValues ...>::value, + F, + typename std::conditional< + IsCallableWith::value, + AddObserverRangeWrapper, + typename std::conditional< + IsCallableWith, TDepValues ...>::value, + AddDefaultReturnValueWrapper, + AddObserverRangeWrapper, + TDepValues...> + >::type + >::type + >::type; + + using TNode = SyncedObserverNode; struct NodeBuilder_ { diff --git a/include/react/detail/graph/ContinuationNodes.h b/include/react/detail/graph/ContinuationNodes.h index ab3c3cd2..c841d23f 100644 --- a/include/react/detail/graph/ContinuationNodes.h +++ b/include/react/detail/graph/ContinuationNodes.h @@ -30,6 +30,36 @@ class SignalNode; template class EventStreamNode; +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// AddContinuationRangeWrapper +/////////////////////////////////////////////////////////////////////////////////////////////////// +template +struct AddContinuationRangeWrapper +{ + AddContinuationRangeWrapper(const AddContinuationRangeWrapper& other) = default; + + AddContinuationRangeWrapper(AddContinuationRangeWrapper&& other) : + MyFunc( std::move(other.MyFunc) ) + {} + + template + < + typename FIn, + class = typename DisableIfSame::type + > + explicit AddContinuationRangeWrapper(FIn&& func) : + MyFunc( std::forward(func) ) + {} + + void operator()(EventRange range, const TArgs& ... args) + { + for (const auto& e : range) + MyFunc(e, args ...); + } + + F MyFunc; +}; + /////////////////////////////////////////////////////////////////////////////////////////////////// /// ContinuationNode /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -171,13 +201,10 @@ class EventContinuationNode : public ContinuationNode // Copy events and func [storedFunc,storedEvents] () mutable { - for (const auto& e : storedEvents) - storedFunc(e); + storedFunc(EventRange( storedEvents )); } ); - TransactionFuncT cont2 = [] { return; }; - DomainSpecificInputManager::Instance() .StoreContinuation( DomainSpecificInputManager::Instance(), @@ -291,10 +318,12 @@ class SyncedContinuationNode : public ContinuationNode // Copy events, func, value tuple (note: 2x copy) [storedFunc,storedEvents,storedValues] () mutable { - for (const auto& e : storedEvents) - { - apply(EvalFunctor_( e, storedFunc ), storedValues); - } + apply( + [&storedFunc,&storedEvents] (const TDepValues& ... vals) + { + storedFunc(EventRange( storedEvents ), vals ...); + }, + storedValues); } }; diff --git a/include/react/detail/graph/EventNodes.h b/include/react/detail/graph/EventNodes.h index 484ed997..bc4eb4b3 100644 --- a/include/react/detail/graph/EventNodes.h +++ b/include/react/detail/graph/EventNodes.h @@ -547,7 +547,7 @@ class EventFlattenNode : public EventStreamNode }; /////////////////////////////////////////////////////////////////////////////////////////////////// -/// SycnedEventTransformNode +/// SyncedEventTransformNode /////////////////////////////////////////////////////////////////////////////////////////////////// template < @@ -590,22 +590,6 @@ class SyncedEventTransformNode : virtual void Tick(void* turnPtr) override { - struct EvalFunctor_ - { - EvalFunctor_(const TIn& e, TFunc& f) : - MyEvent( e ), - MyFunc( f ) - {} - - TOut operator()(const std::shared_ptr>& ... args) - { - return MyFunc(MyEvent, args->ValueRef() ...); - } - - const TIn& MyEvent; - TFunc& MyFunc; - }; - using TurnT = typename D::Engine::TurnT; TurnT& turn = *reinterpret_cast(turnPtr); @@ -617,12 +601,20 @@ class SyncedEventTransformNode : REACT_LOG(D::Log().template Append( GetObjectId(*this), turn.Id())); + // Don't time if there is nothing to do + if (! source_->Events().empty()) {// timer using TimerT = typename SyncedEventTransformNode::ScopedUpdateTimer; TimerT scopedTimer( *this, source_->Events().size() ); for (const auto& e : source_->Events()) - this->events_.push_back(apply(EvalFunctor_( e, func_ ), deps_)); + this->events_.push_back(apply( + [this, &e] (const std::shared_ptr>& ... args) + { + return func_(e, args->ValueRef() ...); + }, + deps_)); + }// ~timer REACT_LOG(D::Log().template Append( @@ -647,7 +639,7 @@ class SyncedEventTransformNode : }; /////////////////////////////////////////////////////////////////////////////////////////////////// -/// SycnedEventFilterNode +/// SyncedEventFilterNode /////////////////////////////////////////////////////////////////////////////////////////////////// template < @@ -689,22 +681,6 @@ class SyncedEventFilterNode : virtual void Tick(void* turnPtr) override { - struct EvalFunctor_ - { - EvalFunctor_(const E& e, TFunc& f) : - MyEvent( e ), - MyFilter( f ) - {} - - bool operator()(const std::shared_ptr>& ... args) - { - return MyFilter(MyEvent, args->ValueRef() ...); - } - - const E& MyEvent; - TFunc& MyFilter; - }; - using TurnT = typename D::Engine::TurnT; TurnT& turn = *reinterpret_cast(turnPtr); @@ -716,12 +692,19 @@ class SyncedEventFilterNode : REACT_LOG(D::Log().template Append( GetObjectId(*this), turn.Id())); + // Don't time if there is nothing to do + if (! source_->Events().empty()) {// timer using TimerT = typename SyncedEventFilterNode::ScopedUpdateTimer; TimerT scopedTimer( *this, source_->Events().size() ); for (const auto& e : source_->Events()) - if (apply(EvalFunctor_( e, filter_ ), deps_)) + if (apply( + [this, &e] (const std::shared_ptr>& ... args) + { + return filter_(e, args->ValueRef() ...); + }, + deps_)) this->events_.push_back(e); }// ~timer @@ -751,6 +734,168 @@ class SyncedEventFilterNode : DepHolderT deps_; }; +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// EventProcessingNode +/////////////////////////////////////////////////////////////////////////////////////////////////// +template +< + typename D, + typename TIn, + typename TOut, + typename TFunc +> +class EventProcessingNode : + public EventStreamNode +{ + using Engine = typename EventProcessingNode::Engine; + +public: + template + EventProcessingNode(const std::shared_ptr>& source, F&& func) : + EventProcessingNode::EventStreamNode( ), + source_( source ), + func_( std::forward(func) ) + { + Engine::OnNodeCreate(*this); + Engine::OnNodeAttach(*this, *source); + } + + ~EventProcessingNode() + { + Engine::OnNodeDetach(*this, *source_); + Engine::OnNodeDestroy(*this); + } + + virtual void Tick(void* turnPtr) override + { + using TurnT = typename D::Engine::TurnT; + TurnT& turn = *reinterpret_cast(turnPtr); + + this->SetCurrentTurn(turn, true); + + REACT_LOG(D::Log().template Append( + GetObjectId(*this), turn.Id())); + + {// timer + using TimerT = typename EventProcessingNode::ScopedUpdateTimer; + TimerT scopedTimer( *this, source_->Events().size() ); + + func_( + EventRange( source_->Events() ), + std::back_inserter(this->events_)); + }// ~timer + + REACT_LOG(D::Log().template Append( + GetObjectId(*this), turn.Id())); + + if (! this->events_.empty()) + Engine::OnNodePulse(*this, turn); + else + Engine::OnNodeIdlePulse(*this, turn); + } + + virtual const char* GetNodeType() const override { return "EventProcessingNode"; } + virtual int DependencyCount() const override { return 1; } + +private: + std::shared_ptr> source_; + + TFunc func_; +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// SyncedEventProcessingNode +/////////////////////////////////////////////////////////////////////////////////////////////////// +template +< + typename D, + typename TIn, + typename TOut, + typename TFunc, + typename ... TDepValues +> +class SyncedEventProcessingNode : + public EventStreamNode +{ + using Engine = typename SyncedEventProcessingNode::Engine; + +public: + template + SyncedEventProcessingNode(const std::shared_ptr>& source, F&& func, + const std::shared_ptr>& ... deps) : + SyncedEventProcessingNode::EventStreamNode( ), + source_( source ), + func_( std::forward(func) ), + deps_( deps ... ) + { + Engine::OnNodeCreate(*this); + Engine::OnNodeAttach(*this, *source); + REACT_EXPAND_PACK(Engine::OnNodeAttach(*this, *deps)); + } + + ~SyncedEventProcessingNode() + { + Engine::OnNodeDetach(*this, *source_); + + apply( + DetachFunctor>...>( *this ), + deps_); + + Engine::OnNodeDestroy(*this); + } + + virtual void Tick(void* turnPtr) override + { + using TurnT = typename D::Engine::TurnT; + TurnT& turn = *reinterpret_cast(turnPtr); + + this->SetCurrentTurn(turn, true); + // Update of this node could be triggered from deps, + // so make sure source doesnt contain events from last turn + source_->SetCurrentTurn(turn); + + REACT_LOG(D::Log().template Append( + GetObjectId(*this), turn.Id())); + + // Don't time if there is nothing to do + if (! source_->Events().empty()) + {// timer + using TimerT = typename SyncedEventProcessingNode::ScopedUpdateTimer; + TimerT scopedTimer( *this, source_->Events().size() ); + + apply( + [this] (const std::shared_ptr>& ... args) + { + func_( + EventRange( source_->Events() ), + std::back_inserter(this->events_)); + }, + deps_); + + }// ~timer + + REACT_LOG(D::Log().template Append( + GetObjectId(*this), turn.Id())); + + if (! this->events_.empty()) + Engine::OnNodePulse(*this, turn); + else + Engine::OnNodeIdlePulse(*this, turn); + } + + virtual const char* GetNodeType() const override { return "SycnedEventProcessingNode"; } + virtual int DependencyCount() const override { return 1 + sizeof...(TDepValues); } + +private: + using DepHolderT = std::tuple>...>; + + std::shared_ptr> source_; + + TFunc func_; + DepHolderT deps_; +}; + /****************************************/ REACT_IMPL_END /***************************************/ #endif // REACT_DETAIL_GRAPH_EVENTNODES_H_INCLUDED \ No newline at end of file diff --git a/include/react/detail/graph/GraphBase.h b/include/react/detail/graph/GraphBase.h index 38979813..9ce6a9ef 100644 --- a/include/react/detail/graph/GraphBase.h +++ b/include/react/detail/graph/GraphBase.h @@ -245,6 +245,30 @@ class ReactiveOpBase DepHolderT deps_; }; +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// Iterators for event processing +/////////////////////////////////////////////////////////////////////////////////////////////////// +template +class EventRange +{ +public: + using const_iterator = typename std::vector::const_iterator; + + EventRange(const EventRange&) = default; + + const_iterator begin() const { return data_.begin(); } + const_iterator end() const { return data_.end(); } + + explicit EventRange(const std::vector& data) : + data_( data ) + {} + +private: + const std::vector& data_; +}; + +template +using EventInserter = std::back_insert_iterator>; /****************************************/ REACT_IMPL_END /***************************************/ diff --git a/include/react/detail/graph/ObserverNodes.h b/include/react/detail/graph/ObserverNodes.h index a2d4c1df..351a54e5 100644 --- a/include/react/detail/graph/ObserverNodes.h +++ b/include/react/detail/graph/ObserverNodes.h @@ -38,6 +38,39 @@ enum class ObserverAction stop_and_detach }; +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// AddObserverRangeWrapper +/////////////////////////////////////////////////////////////////////////////////////////////////// +template +struct AddObserverRangeWrapper +{ + AddObserverRangeWrapper(const AddObserverRangeWrapper& other) = default; + + AddObserverRangeWrapper(AddObserverRangeWrapper&& other) : + MyFunc( std::move(other.MyFunc) ) + {} + + template + < + typename FIn, + class = typename DisableIfSame::type + > + explicit AddObserverRangeWrapper(FIn&& func) : + MyFunc( std::forward(func) ) + {} + + ObserverAction operator()(EventRange range, const TArgs& ... args) + { + for (const auto& e : range) + if (MyFunc(e, args ...) == ObserverAction::stop_and_detach) + return ObserverAction::stop_and_detach; + + return ObserverAction::next; + } + + F MyFunc; +}; + /////////////////////////////////////////////////////////////////////////////////////////////////// /// ObserverNode /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -183,15 +216,9 @@ class EventObserverNode : {// timer using TimerT = typename EventObserverNode::ScopedUpdateTimer; TimerT scopedTimer( *this, p->Events().size() ); - - for (const auto& e : p->Events()) - { - if (func_(e) == ObserverAction::stop_and_detach) - { - shouldDetach = true; - break; - } - } + + shouldDetach = func_(EventRange( p->Events() )) == ObserverAction::stop_and_detach; + }// ~timer if (shouldDetach) @@ -263,22 +290,6 @@ class SyncedObserverNode : virtual void Tick(void* turnPtr) override { - struct EvalFunctor_ - { - EvalFunctor_(const E& e, TFunc& f) : - MyEvent( e ), - MyFunc( f ) - {} - - ObserverAction operator()(const std::shared_ptr>& ... args) - { - return MyFunc(MyEvent, args->ValueRef() ...); - } - - const E& MyEvent; - TFunc& MyFunc; - }; - using TurnT = typename D::Engine::TurnT; TurnT& turn = *reinterpret_cast(turnPtr); @@ -297,14 +308,13 @@ class SyncedObserverNode : using TimerT = typename SyncedObserverNode::ScopedUpdateTimer; TimerT scopedTimer( *this, p->Events().size() ); - for (const auto& e : p->Events()) - { - if (apply(EvalFunctor_( e, func_ ), deps_) == ObserverAction::stop_and_detach) + shouldDetach = apply( + [this, &p] (const std::shared_ptr>& ... args) { - shouldDetach = true; - break; - } - } + return func_(EventRange( p->Events() ), args->ValueRef() ...); + }, + deps_) == ObserverAction::stop_and_detach; + }// ~timer } From 301202026c6cd67314b7ca1f1e60858c5a3804fc Mon Sep 17 00:00:00 2001 From: schlangster Date: Thu, 7 Aug 2014 13:58:06 +0200 Subject: [PATCH 13/75] Improved static_assert error messages. --- include/react/Domain.h | 36 +++++++++++++++++++++++++++--------- include/react/Observer.h | 38 +++++++++++++++++++++++++++----------- 2 files changed, 54 insertions(+), 20 deletions(-) diff --git a/include/react/Domain.h b/include/react/Domain.h index ac049438..8bbf6f00 100644 --- a/include/react/Domain.h +++ b/include/react/Domain.h @@ -195,7 +195,7 @@ auto MakeContinuation(TransactionFlagsT flags, const Signal& trigger, FIn&& -> Continuation { static_assert(DOut::is_concurrent, - "MakeContinuation requires support for concurrent input to target domain."); + "MakeContinuation: Target domain does not support concurrent input."); using REACT_IMPL::SignalContinuationNode; using F = typename std::decay::type; @@ -232,7 +232,7 @@ auto MakeContinuation(TransactionFlagsT flags, const Events& trigger, FIn&& -> Continuation { static_assert(DOut::is_concurrent, - "MakeContinuation requires support for concurrent input to target domain."); + "MakeContinuation: Target domain does not support concurrent input."); using REACT_IMPL::EventContinuationNode; using REACT_IMPL::AddContinuationRangeWrapper; @@ -245,9 +245,16 @@ auto MakeContinuation(TransactionFlagsT flags, const Events& trigger, FIn&& typename std::conditional< IsCallableWith>::value, F, - AddContinuationRangeWrapper + typename std::conditional< + IsCallableWith::value, + AddContinuationRangeWrapper, + void + >::type >::type; + static_assert(! std::is_same::value, + "MakeContinuation: Passed function does not match any of the supported signatures."); + return Continuation( std::make_shared>( flags, GetNodePtr(trigger), std::forward(func))); @@ -282,7 +289,7 @@ auto MakeContinuation(TransactionFlagsT flags, const Events& trigger, -> Continuation { static_assert(DOut::is_concurrent, - "MakeContinuation requires support for concurrent input to target domain."); + "MakeContinuation: Target domain does not support concurrent input."); using REACT_IMPL::SyncedContinuationNode; using REACT_IMPL::AddContinuationRangeWrapper; @@ -295,9 +302,16 @@ auto MakeContinuation(TransactionFlagsT flags, const Events& trigger, typename std::conditional< IsCallableWith, TDepValues ...>::value, F, - AddContinuationRangeWrapper + typename std::conditional< + IsCallableWith::value, + AddContinuationRangeWrapper, + void + >::type >::type; + static_assert(! std::is_same::value, + "MakeContinuation: Passed function does not match any of the supported signatures."); + struct NodeBuilder_ { NodeBuilder_(TransactionFlagsT flags, const Events& trigger, FIn&& func) : @@ -364,7 +378,8 @@ void DoTransaction(TransactionFlagsT flags, F&& func) template void AsyncTransaction(F&& func) { - static_assert(D::is_concurrent, "AsyncTransaction requires concurrent domain."); + static_assert(D::is_concurrent, + "AsyncTransaction: Domain does not support concurrent input."); using REACT_IMPL::DomainSpecificInputManager; DomainSpecificInputManager::Instance() @@ -374,7 +389,8 @@ void AsyncTransaction(F&& func) template void AsyncTransaction(TransactionFlagsT flags, F&& func) { - static_assert(D::is_concurrent, "AsyncTransaction requires concurrent domain."); + static_assert(D::is_concurrent, + "AsyncTransaction: Domain does not support concurrent input."); using REACT_IMPL::DomainSpecificInputManager; DomainSpecificInputManager::Instance() @@ -384,7 +400,8 @@ void AsyncTransaction(TransactionFlagsT flags, F&& func) template void AsyncTransaction(TransactionStatus& status, F&& func) { - static_assert(D::is_concurrent, "AsyncTransaction requires concurrent domain."); + static_assert(D::is_concurrent, + "AsyncTransaction: Domain does not support concurrent input."); using REACT_IMPL::DomainSpecificInputManager; @@ -395,7 +412,8 @@ void AsyncTransaction(TransactionStatus& status, F&& func) template void AsyncTransaction(TransactionFlagsT flags, TransactionStatus& status, F&& func) { - static_assert(D::is_concurrent, "AsyncTransaction requires concurrent domain."); + static_assert(D::is_concurrent, + "AsyncTransaction: Domain does not support concurrent input."); using REACT_IMPL::DomainSpecificInputManager; DomainSpecificInputManager::Instance() diff --git a/include/react/Observer.h b/include/react/Observer.h index 9b50fc6a..45fd78a1 100644 --- a/include/react/Observer.h +++ b/include/react/Observer.h @@ -179,7 +179,7 @@ auto Observe(const Signal& subject, FIn&& func) // If return value of passed function is void, add ObserverAction::next as // default return value. - using TNode = typename std::conditional< + using NodeT = typename std::conditional< std::is_same::value, SignalObserverNode, SignalObserverNode @@ -187,7 +187,7 @@ auto Observe(const Signal& subject, FIn&& func) const auto& subjectPtr = GetNodePtr(subject); - std::unique_ptr> nodePtr( new TNode(subjectPtr, std::forward(func)) ); + std::unique_ptr> nodePtr( new NodeT(subjectPtr, std::forward(func)) ); ObserverNode* rawNodePtr = nodePtr.get(); subjectPtr->RegisterObserver(std::move(nodePtr)); @@ -227,17 +227,25 @@ auto Observe(const Events& subject, FIn&& func) typename std::conditional< IsCallableWith>::value, AddDefaultReturnValueWrapper, - AddObserverRangeWrapper> + typename std::conditional< + IsCallableWith::value, + AddObserverRangeWrapper>, + void + >::type >::type >::type >::type; + + static_assert( + ! std::is_same::value, + "Observe: Passed function does not match any of the supported signatures."); - using TNode = EventObserverNode; + using NodeT = EventObserverNode; const auto& subjectPtr = GetNodePtr(subject); - std::unique_ptr> nodePtr( new TNode(subjectPtr, std::forward(func)) ); + std::unique_ptr> nodePtr( new NodeT(subjectPtr, std::forward(func)) ); ObserverNode* rawNodePtr = nodePtr.get(); subjectPtr->RegisterObserver(std::move(nodePtr)); @@ -279,14 +287,22 @@ auto Observe(const Events& subject, typename std::conditional< IsCallableWith, TDepValues ...>::value, AddDefaultReturnValueWrapper, - AddObserverRangeWrapper, - TDepValues...> + typename std::conditional< + IsCallableWith::value, + AddObserverRangeWrapper, + TDepValues...>, + void + >::type >::type >::type >::type; - using TNode = SyncedObserverNode; + static_assert( + ! std::is_same::value, + "Observe: Passed function does not match any of the supported signatures."); + + using NodeT = SyncedObserverNode; struct NodeBuilder_ { @@ -298,7 +314,7 @@ auto Observe(const Events& subject, auto operator()(const Signal& ... deps) -> ObserverNode* { - return new TNode( + return new NodeT( GetNodePtr(MySubject), std::forward(MyFunc), GetNodePtr(deps) ... ); } From 794835380609f3c5c54b306e69eb432e77a741dd Mon Sep 17 00:00:00 2001 From: schlangster Date: Thu, 7 Aug 2014 13:58:46 +0200 Subject: [PATCH 14/75] Added some convenience functions to EventRange. --- include/react/detail/graph/GraphBase.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/react/detail/graph/GraphBase.h b/include/react/detail/graph/GraphBase.h index 9ce6a9ef..2adf8160 100644 --- a/include/react/detail/graph/GraphBase.h +++ b/include/react/detail/graph/GraphBase.h @@ -253,12 +253,16 @@ class EventRange { public: using const_iterator = typename std::vector::const_iterator; + using size_type = typename std::vector::size_type; EventRange(const EventRange&) = default; const_iterator begin() const { return data_.begin(); } const_iterator end() const { return data_.end(); } + size_type Size() const { return data_.size(); } + bool IsEmpty() const { return data_.empty(); } + explicit EventRange(const std::vector& data) : data_( data ) {} From 3ff8cdcba524692536e0096ae25604f73228ad47 Mon Sep 17 00:00:00 2001 From: schlangster Date: Thu, 7 Aug 2014 13:59:29 +0200 Subject: [PATCH 15/75] Added EventRange support to Iterate. --- include/react/Algorithm.h | 78 +++++++++--- include/react/detail/graph/AlgorithmNodes.h | 124 ++++++++++++-------- 2 files changed, 138 insertions(+), 64 deletions(-) diff --git a/include/react/Algorithm.h b/include/react/Algorithm.h index 2f0e7730..7caed812 100644 --- a/include/react/Algorithm.h +++ b/include/react/Algorithm.h @@ -77,7 +77,7 @@ auto Monitor(const Signal& target) } /////////////////////////////////////////////////////////////////////////////////////////////////// -/// Iterate - Iteratively combines signal value with values from event stream +/// Iterate - Iteratively combines signal value with values from event stream (aka Fold) /////////////////////////////////////////////////////////////////////////////////////////////////// template < @@ -92,17 +92,38 @@ auto Iterate(const Events& events, V&& init, FIn&& func) { using REACT_IMPL::IterateNode; using REACT_IMPL::IterateByRefNode; + using REACT_IMPL::AddIterateRangeWrapper; + using REACT_IMPL::AddIterateByRefRangeWrapper; + using REACT_IMPL::IsCallableWith; + using REACT_IMPL::EventRange; using F = typename std::decay::type; - using R = typename std::result_of::type; - using TNode = typename std::conditional< - std::is_same::value, - IterateByRefNode, - IterateNode - >::type; + + using NodeT = + typename std::conditional< + IsCallableWith,S>::value, + IterateNode, + typename std::conditional< + IsCallableWith::value, + IterateNode>, + typename std::conditional< + IsCallableWith, S&>::value, + IterateByRefNode, + typename std::conditional< + IsCallableWith::value, + IterateByRefNode>, + void + >::type + >::type + >::type + >::type; + + static_assert( + ! std::is_same::value, + "Iterate: Passed function does not match any of the supported signatures."); return Signal( - std::make_shared( + std::make_shared( std::forward(init), GetNodePtr(events), std::forward(func))); } @@ -124,14 +145,41 @@ auto Iterate(const Events& events, V&& init, { using REACT_IMPL::SyncedIterateNode; using REACT_IMPL::SyncedIterateByRefNode; + using REACT_IMPL::AddIterateRangeWrapper; + using REACT_IMPL::AddIterateByRefRangeWrapper; + using REACT_IMPL::IsCallableWith; + using REACT_IMPL::EventRange; using F = typename std::decay::type; - using R = typename std::result_of::type; - using TNode = typename std::conditional< - std::is_same::value, - SyncedIterateByRefNode, - SyncedIterateNode - >::type; + + using NodeT = + typename std::conditional< + IsCallableWith,S,TDepValues ...>::value, + SyncedIterateNode, + typename std::conditional< + IsCallableWith::value, + SyncedIterateNode, + TDepValues ...>, + typename std::conditional< + IsCallableWith,S&,TDepValues ...>::value, + SyncedIterateByRefNode, + typename std::conditional< + IsCallableWith::value, + SyncedIterateByRefNode, + TDepValues ...>, + void + >::type + >::type + >::type + >::type; + + static_assert( + ! std::is_same::value, + "Iterate: Passed function does not match any of the supported signatures."); + + //static_assert(NodeT::dummy_error, "DUMP MY TYPE" ); struct NodeBuilder_ { @@ -145,7 +193,7 @@ auto Iterate(const Events& events, V&& init, -> Signal { return Signal( - std::make_shared( + std::make_shared( std::forward(MyInit), GetNodePtr(MySource), std::forward(MyFunc), GetNodePtr(deps) ...)); } diff --git a/include/react/detail/graph/AlgorithmNodes.h b/include/react/detail/graph/AlgorithmNodes.h index fc89aaf9..3c061c68 100644 --- a/include/react/detail/graph/AlgorithmNodes.h +++ b/include/react/detail/graph/AlgorithmNodes.h @@ -19,6 +19,65 @@ /***************************************/ REACT_IMPL_BEGIN /**************************************/ +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// AddIterateRangeWrapper +/////////////////////////////////////////////////////////////////////////////////////////////////// +template +struct AddIterateRangeWrapper +{ + AddIterateRangeWrapper(const AddIterateRangeWrapper& other) = default; + + AddIterateRangeWrapper(AddIterateRangeWrapper&& other) : + MyFunc( std::move(other.MyFunc) ) + {} + + template + < + typename FIn, + class = typename DisableIfSame::type + > + explicit AddIterateRangeWrapper(FIn&& func) : + MyFunc( std::forward(func) ) + {} + + S operator()(EventRange range, S value, const TArgs& ... args) + { + for (const auto& e : range) + value = MyFunc(e, value, args ...); + + return value; + } + + F MyFunc; +}; + +template +struct AddIterateByRefRangeWrapper +{ + AddIterateByRefRangeWrapper(const AddIterateByRefRangeWrapper& other) = default; + + AddIterateByRefRangeWrapper(AddIterateByRefRangeWrapper&& other) : + MyFunc( std::move(other.MyFunc) ) + {} + + template + < + typename FIn, + class = typename DisableIfSame::type + > + explicit AddIterateByRefRangeWrapper(FIn&& func) : + MyFunc( std::forward(func) ) + {} + + void operator()(EventRange range, S& valueRef, const TArgs& ... args) + { + for (const auto& e : range) + MyFunc(e, valueRef, args ...); + } + + F MyFunc; +}; + /////////////////////////////////////////////////////////////////////////////////////////////////// /// IterateNode /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -65,10 +124,7 @@ class IterateNode : using TimerT = typename IterateNode::ScopedUpdateTimer; TimerT scopedTimer( *this, events_->Events().size() ); - S newValue = this->value_; - - for (const auto& e : events_->Events()) - newValue = func_(e, newValue); + S newValue = func_(EventRange( events_->Events() ), this->value_); if (! Equals(newValue, this->value_)) { @@ -139,8 +195,8 @@ class IterateByRefNode : using TimerT = typename IterateByRefNode::ScopedUpdateTimer; TimerT scopedTimer( *this, events_->Events().size() ); - for (const auto& e : events_->Events()) - func_(e, this->value_); + func_(EventRange( events_->Events() ), this->value_); + }// ~timer REACT_LOG(D::Log().template Append( @@ -203,24 +259,6 @@ class SyncedIterateNode : virtual void Tick(void* turnPtr) override { - struct EvalFunctor_ - { - EvalFunctor_(const E& e, const S& v, TFunc& f) : - MyEvent( e ), - MyValue( v ), - MyFunc( f ) - {} - - S operator()(const std::shared_ptr>& ... args) - { - return MyFunc(MyEvent, MyValue, args->ValueRef() ...); - } - - const E& MyEvent; - const S& MyValue; - TFunc& MyFunc; - }; - using TurnT = typename D::Engine::TurnT; TurnT& turn = *reinterpret_cast(turnPtr); @@ -235,11 +273,13 @@ class SyncedIterateNode : {// timer using TimerT = typename SyncedIterateNode::ScopedUpdateTimer; TimerT scopedTimer( *this, events_->Events().size() ); - - S newValue = this->value_; - - for (const auto& e : events_->Events()) - newValue = apply(EvalFunctor_( e, std::move(newValue), func_ ), deps_); + + S newValue = apply( + [this] (const std::shared_ptr>& ... args) + { + return func_(EventRange( events_->Events() ), this->value_, args->ValueRef() ...); + }, + deps_); if (! Equals(newValue, this->value_)) { @@ -313,24 +353,6 @@ class SyncedIterateByRefNode : virtual void Tick(void* turnPtr) override { - struct EvalFunctor_ - { - EvalFunctor_(const E& e, S& v, TFunc& f) : - MyEvent( e ), - MyValue( v ), - MyFunc( f ) - {} - - void operator()(const std::shared_ptr>& ... args) - { - MyFunc(MyEvent, MyValue, args->ValueRef() ...); - } - - const E& MyEvent; - S& MyValue; - TFunc& MyFunc; - }; - using TurnT = typename D::Engine::TurnT; TurnT& turn = *reinterpret_cast(turnPtr); @@ -346,8 +368,12 @@ class SyncedIterateByRefNode : using TimerT = typename SyncedIterateByRefNode::ScopedUpdateTimer; TimerT scopedTimer( *this, events_->Events().size() ); - for (const auto& e : events_->Events()) - apply(EvalFunctor_( e, this->value_, func_ ), deps_); + apply( + [this] (const std::shared_ptr>& ... args) + { + func_(EventRange( events_->Events() ), this->value_, args->ValueRef() ...); + }, + deps_); changed = true; }// ~timer From 33ba9c3c283d5334d1fdba3bd4fcf300a76610e7 Mon Sep 17 00:00:00 2001 From: schlangster Date: Thu, 7 Aug 2014 14:00:08 +0200 Subject: [PATCH 16/75] Added test cases for EventRange Iterate. --- tests/src/OperationsTest.h | 222 +++++++++++++++++++++++++++++++++++++ 1 file changed, 222 insertions(+) diff --git a/tests/src/OperationsTest.h b/tests/src/OperationsTest.h index 87c54f35..a10167c8 100644 --- a/tests/src/OperationsTest.h +++ b/tests/src/OperationsTest.h @@ -586,6 +586,226 @@ TYPED_TEST_P(OperationsTest, SyncedIterate2) } } +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// SyncedIterate3 test (event range) +/////////////////////////////////////////////////////////////////////////////////////////////////// +TYPED_TEST_P(OperationsTest, SyncedIterate3) +{ + using D = typename SyncedIterate3::MyDomain; + + auto in1 = MakeVar(1); + auto in2 = MakeVar(1); + + auto op1 = in1 + in2; + auto op2 = (in1 + in2) * 10; + + auto src1 = MakeEventSource(); + auto src2 = MakeEventSource(); + + auto out1 = Iterate( + src1, + make_tuple(0,0), + With(op1,op2), + [] (EventRange range, const tuple& t, int op1, int op2) { + return make_tuple( + get<0>(t) + (op1 * range.Size()), + get<1>(t) + (op2 * range.Size())); + }); + + auto out2 = Iterate( + src2, + make_tuple(0,0,0), + With(op1,op2), + [] (EventRange range, const tuple& t, int op1, int op2) { + int sum = 0; + for (const auto& e : range) + sum += e; + + return make_tuple( + get<0>(t) + sum, + get<1>(t) + (op1 * range.Size()), + get<2>(t) + (op2 * range.Size())); + }); + + int obsCount1 = 0; + int obsCount2 = 0; + + { + auto obs1 = Observe(out1, [&] (const tuple& t) { + ++obsCount1; + + ASSERT_EQ(get<0>(t), 33); + ASSERT_EQ(get<1>(t), 330); + }); + + auto obs2 = Observe(out2, [&] (const tuple& t) { + ++obsCount2; + + ASSERT_EQ(get<0>(t), 42); + ASSERT_EQ(get<1>(t), 33); + ASSERT_EQ(get<2>(t), 330); + }); + + in1 <<= 22; + in2 <<= 11; + + src1.Emit(); + src2.Emit(42); + + ASSERT_EQ(obsCount1, 1); + ASSERT_EQ(obsCount2, 1); + + obs1.Detach(); + obs2.Detach(); + } + + { + auto obs1 = Observe(out1, [&] (const tuple& t) { + ++obsCount1; + + ASSERT_EQ(get<0>(t), 33 + 330); + ASSERT_EQ(get<1>(t), 330 + 3300); + }); + + auto obs2 = Observe(out2, [&] (const tuple& t) { + ++obsCount2; + + ASSERT_EQ(get<0>(t), 42 + 420); + ASSERT_EQ(get<1>(t), 33 + 330); + ASSERT_EQ(get<2>(t), 330 + 3300); + }); + + in1 <<= 220; + in2 <<= 110; + + src1.Emit(); + src2.Emit(420); + + ASSERT_EQ(obsCount1, 2); + ASSERT_EQ(obsCount2, 2); + + obs1.Detach(); + obs2.Detach(); + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// SyncedIterate4 test (event range, by ref) +/////////////////////////////////////////////////////////////////////////////////////////////////// +TYPED_TEST_P(OperationsTest, SyncedIterate4) +{ + using D = typename SyncedIterate4::MyDomain; + + auto in1 = MakeVar(1); + auto in2 = MakeVar(1); + + auto op1 = in1 + in2; + auto op2 = (in1 + in2) * 10; + + auto src1 = MakeEventSource(); + auto src2 = MakeEventSource(); + + auto out1 = Iterate( + src1, + vector{}, + With(op1,op2), + [] (EventRange range, vector& v, int op1, int op2) -> void { + for (const auto& e : range) + { + v.push_back(op1); + v.push_back(op2); + } + }); + + auto out2 = Iterate( + src2, + vector{}, + With(op1,op2), + [] (EventRange range, vector& v, int op1, int op2) -> void { + for (const auto& e : range) + { + v.push_back(e); + v.push_back(op1); + v.push_back(op2); + } + }); + + int obsCount1 = 0; + int obsCount2 = 0; + + { + auto obs1 = Observe(out1, [&] (const vector& v) { + ++obsCount1; + + ASSERT_EQ(v.size(), 2); + + ASSERT_EQ(v[0], 33); + ASSERT_EQ(v[1], 330); + }); + + auto obs2 = Observe(out2, [&] (const vector& v) { + ++obsCount2; + + ASSERT_EQ(v.size(), 3); + + ASSERT_EQ(v[0], 42); + ASSERT_EQ(v[1], 33); + ASSERT_EQ(v[2], 330); + }); + + in1 <<= 22; + in2 <<= 11; + + src1.Emit(); + src2.Emit(42); + + ASSERT_EQ(obsCount1, 1); + ASSERT_EQ(obsCount2, 1); + + obs1.Detach(); + obs2.Detach(); + } + + { + auto obs1 = Observe(out1, [&] (const vector& v) { + ++obsCount1; + + ASSERT_EQ(v.size(), 4); + + ASSERT_EQ(v[0], 33); + ASSERT_EQ(v[1], 330); + ASSERT_EQ(v[2], 330); + ASSERT_EQ(v[3], 3300); + }); + + auto obs2 = Observe(out2, [&] (const vector& v) { + ++obsCount2; + + ASSERT_EQ(v.size(), 6); + + ASSERT_EQ(v[0], 42); + ASSERT_EQ(v[1], 33); + ASSERT_EQ(v[2], 330); + + ASSERT_EQ(v[3], 420); + ASSERT_EQ(v[4], 330); + ASSERT_EQ(v[5], 3300); + }); + + in1 <<= 220; + in2 <<= 110; + + src1.Emit(); + src2.Emit(420); + + ASSERT_EQ(obsCount1, 2); + ASSERT_EQ(obsCount2, 2); + + obs1.Detach(); + obs2.Detach(); + } +} + /////////////////////////////////////////////////////////////////////////////////////////////////// /// EventFilter1 /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -688,6 +908,8 @@ REGISTER_TYPED_TEST_CASE_P SyncedTransform1, SyncedIterate1, SyncedIterate2, + SyncedIterate3, + SyncedIterate4, SyncedEventFilter1, SyncedEventTransform1 ); From eadf7f370850b474d02a0f84f007beee761efb97 Mon Sep 17 00:00:00 2001 From: schlangster Date: Fri, 8 Aug 2014 01:17:23 +0200 Subject: [PATCH 17/75] IsCallableWith had problems with function pointers on MSVC. Using a different SFINAE method fixed it. --- include/react/common/Util.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/include/react/common/Util.h b/include/react/common/Util.h index b50c005b..39741ed7 100644 --- a/include/react/common/Util.h +++ b/include/react/common/Util.h @@ -206,10 +206,14 @@ class IsCallableWith using NoT = char[1]; using YesT = char[2]; - template - static YesT& check( - decltype( static_cast( - (std::declval())(std::declval() ...))) *); + template + < + typename U, + class = decltype( + static_cast( + (std::declval())(std::declval() ...))) + > + static YesT& check(void*); template static NoT& check(...); From c3ec931be5390913a567cb10248f22aee46a63f5 Mon Sep 17 00:00:00 2001 From: schlangster Date: Fri, 8 Aug 2014 01:45:46 +0200 Subject: [PATCH 18/75] Added test cases Process. --- tests/src/EventStreamTest.h | 53 ++++++++++++++++++++++++++++++++- tests/src/OperationsTest.h | 58 +++++++++++++++++++++++++++++++++++-- 2 files changed, 108 insertions(+), 3 deletions(-) diff --git a/tests/src/EventStreamTest.h b/tests/src/EventStreamTest.h index 55a67124..39e2479d 100644 --- a/tests/src/EventStreamTest.h +++ b/tests/src/EventStreamTest.h @@ -269,6 +269,56 @@ TYPED_TEST_P(EventStreamTest, EventTransform) ASSERT_TRUE(std::find(results.begin(), results.end(), "HELLO VORLD") != results.end()); } +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// EventProcess test +/////////////////////////////////////////////////////////////////////////////////////////////////// +TYPED_TEST_P(EventStreamTest, EventProcess) +{ + using D = typename EventProcess::MyDomain; + + std::vector results; + + auto in1 = MakeEventSource(); + auto in2 = MakeEventSource(); + + auto merged = Merge(in1, in2); + int callCount = 0; + + auto processed = Process(merged, + [&] (EventRange range, EventInserter out) + { + for (const auto& e : range) + { + *out = 0.1f * e; + *out = 1.5f * e; + } + + callCount++; + }); + + Observe(processed, + [&] (float s) + { + results.push_back(s); + }); + + DoTransaction([&] { + in1 << 10 << 20; + }); + + in2 << 30; + + ASSERT_EQ(results.size(), 6); + ASSERT_EQ(callCount, 2); + + ASSERT_EQ(results[0], 1.0f); + ASSERT_EQ(results[1], 15.0f); + ASSERT_EQ(results[2], 2.0f); + ASSERT_EQ(results[3], 30.0f); + ASSERT_EQ(results[4], 3.0f); + ASSERT_EQ(results[5], 45.0f); +} + /////////////////////////////////////////////////////////////////////////////////////////////////// REGISTER_TYPED_TEST_CASE_P ( @@ -278,7 +328,8 @@ REGISTER_TYPED_TEST_CASE_P EventMerge2, EventMerge3, EventFilter, - EventTransform + EventTransform, + EventProcess ); } // ~namespace diff --git a/tests/src/OperationsTest.h b/tests/src/OperationsTest.h index a10167c8..77e8c399 100644 --- a/tests/src/OperationsTest.h +++ b/tests/src/OperationsTest.h @@ -847,7 +847,7 @@ TYPED_TEST_P(OperationsTest, SyncedEventFilter1) } /////////////////////////////////////////////////////////////////////////////////////////////////// -/// EventTransform1 +/// SyncedEventTransform1 /////////////////////////////////////////////////////////////////////////////////////////////////// TYPED_TEST_P(OperationsTest, SyncedEventTransform1) { @@ -892,6 +892,59 @@ TYPED_TEST_P(OperationsTest, SyncedEventTransform1) ASSERT_TRUE(std::find(results.begin(), results.end(), "HELLO VORLD, Alice Anderson") != results.end()); } +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// SyncedEventProcess1 +/////////////////////////////////////////////////////////////////////////////////////////////////// +TYPED_TEST_P(OperationsTest, SyncedEventProcess1) +{ + using D = typename SyncedEventProcess1::MyDomain; + + std::vector results; + + auto in1 = MakeEventSource(); + auto in2 = MakeEventSource(); + + auto mult = MakeVar(10); + + auto merged = Merge(in1, in2); + int callCount = 0; + + auto processed = Process(merged, + With(mult), + [&] (EventRange range, EventInserter out, int mult) + { + for (const auto& e : range) + { + *out = 0.1f * e * mult; + *out = 1.5f * e * mult; + } + + callCount++; + }); + + Observe(processed, + [&] (float s) + { + results.push_back(s); + }); + + DoTransaction([&] { + in1 << 10 << 20; + }); + + in2 << 30; + + ASSERT_EQ(results.size(), 6); + ASSERT_EQ(callCount, 2); + + ASSERT_EQ(results[0], 10.0f); + ASSERT_EQ(results[1], 150.0f); + ASSERT_EQ(results[2], 20.0f); + ASSERT_EQ(results[3], 300.0f); + ASSERT_EQ(results[4], 30.0f); + ASSERT_EQ(results[5], 450.0f); +} + /////////////////////////////////////////////////////////////////////////////////////////////////// REGISTER_TYPED_TEST_CASE_P ( @@ -911,7 +964,8 @@ REGISTER_TYPED_TEST_CASE_P SyncedIterate3, SyncedIterate4, SyncedEventFilter1, - SyncedEventTransform1 + SyncedEventTransform1, + SyncedEventProcess1 ); } // ~namespace From 2acc6ece1d36aa8a44effb8efe843a81f4175b89 Mon Sep 17 00:00:00 2001 From: schlangster Date: Fri, 8 Aug 2014 01:46:38 +0200 Subject: [PATCH 19/75] Fixed synced Process + cleanup. --- include/react/detail/graph/AlgorithmNodes.h | 2 +- include/react/detail/graph/EventNodes.h | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/include/react/detail/graph/AlgorithmNodes.h b/include/react/detail/graph/AlgorithmNodes.h index 3c061c68..454fdfbb 100644 --- a/include/react/detail/graph/AlgorithmNodes.h +++ b/include/react/detail/graph/AlgorithmNodes.h @@ -124,7 +124,7 @@ class IterateNode : using TimerT = typename IterateNode::ScopedUpdateTimer; TimerT scopedTimer( *this, events_->Events().size() ); - S newValue = func_(EventRange( events_->Events() ), this->value_); + S newValue = func_(EventRange( events_->Events() ), this->value_); if (! Equals(newValue, this->value_)) { diff --git a/include/react/detail/graph/EventNodes.h b/include/react/detail/graph/EventNodes.h index bc4eb4b3..499cda24 100644 --- a/include/react/detail/graph/EventNodes.h +++ b/include/react/detail/graph/EventNodes.h @@ -783,6 +783,7 @@ class EventProcessingNode : func_( EventRange( source_->Events() ), std::back_inserter(this->events_)); + }// ~timer REACT_LOG(D::Log().template Append( @@ -869,7 +870,8 @@ class SyncedEventProcessingNode : { func_( EventRange( source_->Events() ), - std::back_inserter(this->events_)); + std::back_inserter(this->events_), + args->ValueRef() ...); }, deps_); From c29d50e7128a8052705285d6e3fe963190ce9f1a Mon Sep 17 00:00:00 2001 From: schlangster Date: Sat, 9 Aug 2014 14:38:20 +0200 Subject: [PATCH 20/75] Async queue no longer uses a dedicated worker thread. Instead, a task is started as soon as there are items in the queue and stopped once it's empty. --- include/react/detail/ReactiveInput.h | 177 ++++++++++++++++++++++----- 1 file changed, 147 insertions(+), 30 deletions(-) diff --git a/include/react/detail/ReactiveInput.h b/include/react/detail/ReactiveInput.h index dbab6b1f..3589d8c7 100644 --- a/include/react/detail/ReactiveInput.h +++ b/include/react/detail/ReactiveInput.h @@ -19,10 +19,10 @@ #include #include #include -#include #include #include +#include "tbb/task.h" #include "tbb/concurrent_queue.h" #include "tbb/enumerable_thread_specific.h" #include "tbb/queuing_mutex.h" @@ -39,6 +39,9 @@ struct IInputNode; class IObserver; +template +class InputManager; + /////////////////////////////////////////////////////////////////////////////////////////////////// /// Common types & constants /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -478,37 +481,142 @@ class TransactionQueue }; /////////////////////////////////////////////////////////////////////////////////////////////////// -/// InputManager +/// AsyncWorker /////////////////////////////////////////////////////////////////////////////////////////////////// +struct AsyncItem +{ + TransactionFlagsT Flags; + WaitingStatePtrT WaitingStatePtr; + TransactionFuncT Func; +}; + +// Interface +template +class AsyncWorker +{ +public: + AsyncWorker(InputManager& mgr); + + void PushItem(AsyncItem&& item); + + void PopItem(AsyncItem& item); + bool TryPopItem(AsyncItem& item); + + bool IncrementItemCount(size_t n); + bool DecrementItemCount(size_t n); + + void Start(); +}; + +// Disabled template -class InputManager : - public IContinuationTarget +struct AsyncWorker { -private: - struct AsyncItem +public: + AsyncWorker(InputManager& mgr) + {} + + void PushItem(AsyncItem&& item) { assert(false); } + + void PopItem(AsyncItem& item) { assert(false); } + bool TryPopItem(AsyncItem& item) { assert(false); return false; } + + bool IncrementItemCount(size_t n) { assert(false); return false; } + bool DecrementItemCount(size_t n) { assert(false); return false; } + + void Start() { assert(false); } +}; + +// Enabled +template +struct AsyncWorker +{ + using DataT = tbb::concurrent_bounded_queue; + + class WorkerTask : public tbb::task { - TransactionFlagsT Flags; - WaitingStatePtrT WaitingStatePtr; - TransactionFuncT Func; + public: + WorkerTask(InputManager& mgr) : + mgr_( mgr ) + {} + + tbb::task* execute() + { + mgr_.processAsyncQueue(); + return nullptr; + } + + private: + InputManager& mgr_; }; - using AsyncQueueT = tbb::concurrent_bounded_queue; +public: + AsyncWorker(InputManager& mgr) : + mgr_( mgr ) + {} + + void PushItem(AsyncItem&& item) + { + data_.push(std::move(item)); + } + void PopItem(AsyncItem& item) + { + data_.pop(item); + } + + bool TryPopItem(AsyncItem& item) + { + return data_.try_pop(item); + } + + bool IncrementItemCount(size_t n) + { + return count_.fetch_add(n, std::memory_order_relaxed) == 0; + } + + bool DecrementItemCount(size_t n) + { + return count_.fetch_sub(n, std::memory_order_relaxed) == n; + } + + void Start() + { + tbb::task::enqueue(*new(tbb::task::allocate_root()) WorkerTask(mgr_)); + } + +private: + DataT data_; + std::atomic count_{ 0 }; + + InputManager& mgr_; +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// InputManager +/////////////////////////////////////////////////////////////////////////////////////////////////// +template +class InputManager : + public IContinuationTarget +{ +private: // Select between thread-safe and non thread-safe implementations using TransactionQueueT = TransactionQueue; + using QueueEntryT = typename TransactionQueueT::QueueEntry; + using ContinuationManagerT = ContinuationManager; + using AsyncWorkerT = AsyncWorker; - using QueueEntryT = typename TransactionQueueT::QueueEntry; + template + friend class AsyncWorker; public: using TurnT = typename D::TurnT; using Engine = typename D::Engine; InputManager() : - asyncWorker_( [this] { processAsyncQueue(); } ) - { - asyncWorker_.detach(); - } + asyncWorker_(*this) + {} template void DoTransaction(TransactionFlagsT flags, F&& func) @@ -556,7 +664,10 @@ class InputManager : if (waitingStatePtr != nullptr) waitingStatePtr->IncWaitCount(); - asyncQueue_.push(AsyncItem{ flags, waitingStatePtr, std::forward(func) } ); + asyncWorker_.PushItem(AsyncItem{ flags, waitingStatePtr, std::forward(func) }); + + if (asyncWorker_.IncrementItemCount(1)) + asyncWorker_.Start(); } template @@ -702,11 +813,20 @@ class InputManager : while (true) { - // Blocks if queue is empty + size_t popCount = 0; + if (!skipPop) - asyncQueue_.pop(item); + { + // Blocks if queue is empty. + // This should never happen, + // and if (maybe due to some memory access internals), only briefly + asyncWorker_.PopItem(item); + popCount++; + } else + { skipPop = false; + } // First try to merge to an existing synchronous item in the queue bool canMerge = (item.Flags & allow_merging) != 0; @@ -745,8 +865,10 @@ class InputManager : { uint extraCount = 0; // Todo: Make configurable - while (extraCount < 512 && asyncQueue_.try_pop(item)) + while (extraCount < 1024 && asyncWorker_.TryPopItem(item)) { + ++popCount; + bool canMergeNext = (item.Flags & allow_merging) != 0; if (canMergeNext) { @@ -786,10 +908,6 @@ class InputManager : continuationManager_.template DetachQueuedObservers(); - //printf("1\n"); - //for (const auto& p : waitingStatePtrs) - // printf("%08X\n", p.Get()); - // Has continuations? If so, status ptrs have to be passed on to // continuation transactions if (continuationManager_.HasContinuations()) @@ -800,10 +918,6 @@ class InputManager : // More than 1 waiting state -> create collection from vector if (waitingStatePtrs.size() > 1) { - /* printf("2\n"); - for (const auto& p : waitingStatePtrs) - printf("%08X\n", p.Get());*/ - WaitingStatePtrT p ( SharedWaitingStateCollection::Create(std::move(waitingStatePtrs)) @@ -839,14 +953,17 @@ class InputManager : } waitingStatePtrs.clear(); + + // Stop this task if the number of items has just been decremented zero. + // A new task will be started by the thread that increments the item count from zero. + if (asyncWorker_.DecrementItemCount(popCount)) + break; } } TransactionQueueT transactionQueue_; ContinuationManagerT continuationManager_; - - AsyncQueueT asyncQueue_; - std::thread asyncWorker_; + AsyncWorkerT asyncWorker_; std::atomic nextTurnId_{ 0 }; From 4538dd90f3f90dee8643d63124225779fbc99947 Mon Sep 17 00:00:00 2001 From: schlangster Date: Sun, 10 Aug 2014 00:26:52 +0200 Subject: [PATCH 21/75] Added event operation: Join. Joins two streams A,B to tuple. Values are buffered for each input slot and emitted once a tuple is complete. --- include/react/Event.h | 24 ++++- include/react/detail/graph/EventNodes.h | 129 ++++++++++++++++++++++++ 2 files changed, 151 insertions(+), 2 deletions(-) diff --git a/include/react/Event.h b/include/react/Event.h index e3f70f3e..777935e9 100644 --- a/include/react/Event.h +++ b/include/react/Event.h @@ -60,7 +60,6 @@ auto MakeEventSource() /////////////////////////////////////////////////////////////////////////////////////////////////// /// Merge /////////////////////////////////////////////////////////////////////////////////////////////////// -// Note: Default template arguments are in forward declaration template < typename D, @@ -77,7 +76,7 @@ auto Merge(const Events& arg1, const Events& ... args) using REACT_IMPL::EventOpNode; static_assert(sizeof...(TArgs) > 0, - "react::Merge requires at least 2 arguments."); + "Merge: 2+ arguments are required."); return TempEvents( std::make_shared>( @@ -427,6 +426,27 @@ auto Flatten(const Signal>& outer) GetNodePtr(outer), GetNodePtr(outer.Value()))); } +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// Join +/////////////////////////////////////////////////////////////////////////////////////////////////// +template +< + typename D, + typename ... TArgs +> +auto Join(const Events& ... args) + -> Events> +{ + using REACT_IMPL::EventJoinNode; + + static_assert(sizeof...(TArgs) > 1, + "Join: 2+ arguments are required."); + + return Events>( + std::make_shared>( + GetNodePtr(args) ...)); +} + /////////////////////////////////////////////////////////////////////////////////////////////////// /// Token /////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/include/react/detail/graph/EventNodes.h b/include/react/detail/graph/EventNodes.h index 499cda24..850b36c2 100644 --- a/include/react/detail/graph/EventNodes.h +++ b/include/react/detail/graph/EventNodes.h @@ -898,6 +898,135 @@ class SyncedEventProcessingNode : DepHolderT deps_; }; +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// EventJoinNode +/////////////////////////////////////////////////////////////////////////////////////////////////// +template +< + typename D, + typename ... TValues +> +class EventJoinNode : + public EventStreamNode> +{ + using Engine = typename EventJoinNode::Engine; + using TurnT = typename Engine::TurnT; + +public: + EventJoinNode(const std::shared_ptr>& ... sources) : + EventJoinNode::EventStreamNode( ), + slots_( sources ... ) + { + Engine::OnNodeCreate(*this); + REACT_EXPAND_PACK(Engine::OnNodeAttach(*this, *sources)); + } + + ~EventJoinNode() + { + apply( + [this] (Slot& ... slots) { + REACT_EXPAND_PACK(Engine::OnNodeDetach(*this, *slots.Source)); + }, + slots_); + + Engine::OnNodeDestroy(*this); + } + + virtual void Tick(void* turnPtr) override + { + TurnT& turn = *reinterpret_cast(turnPtr); + + this->SetCurrentTurn(turn, true); + + REACT_LOG(D::Log().template Append( + GetObjectId(*this), turn.Id())); + + // Don't time if there is nothing to do + {// timer + size_t count = 0; + using TimerT = typename EventJoinNode::ScopedUpdateTimer; + TimerT scopedTimer( *this, count ); + + // Move events into buffers + apply( + [this, &turn] (Slot& ... slots) { + REACT_EXPAND_PACK(fetchBuffer(turn, slots)); + }, + slots_); + + while (true) + { + bool isReady = true; + + // All slots ready? + apply( + [this,&isReady] (Slot& ... slots) { + // Todo: combine return values instead + REACT_EXPAND_PACK(checkSlot(slots, isReady)); + }, + slots_); + + if (!isReady) + break; + + // Pop values from buffers and emit tuple + apply( + [this] (Slot& ... slots) { + this->events_.emplace_back(slots.Buffer.front() ...); + REACT_EXPAND_PACK(slots.Buffer.pop_front()); + }, + slots_); + } + + count = this->events_.size(); + + }// ~timer + + REACT_LOG(D::Log().template Append( + GetObjectId(*this), turn.Id())); + + if (! this->events_.empty()) + Engine::OnNodePulse(*this, turn); + else + Engine::OnNodeIdlePulse(*this, turn); + } + + virtual const char* GetNodeType() const override { return "EventJoinNode"; } + virtual int DependencyCount() const override { return sizeof...(TValues); } + +private: + template + struct Slot + { + Slot(const std::shared_ptr>& src) : + Source( src ) + {} + + std::shared_ptr> Source; + std::deque Buffer; + }; + + template + static void fetchBuffer(TurnT& turn, Slot& slot) + { + slot.Source->SetCurrentTurn(turn); + + slot.Buffer.insert( + slot.Buffer.end(), + slot.Source->Events().begin(), + slot.Source->Events().end()); + } + + template + static void checkSlot(Slot& slot, bool& isReady) + { + auto t = isReady && !slot.Buffer.empty(); + isReady = t; + } + + std::tuple...> slots_; +}; + /****************************************/ REACT_IMPL_END /***************************************/ #endif // REACT_DETAIL_GRAPH_EVENTNODES_H_INCLUDED \ No newline at end of file From bad1c7940f329e23b935b1f40ef1d2e76068cd51 Mon Sep 17 00:00:00 2001 From: schlangster Date: Mon, 12 Jan 2015 17:54:34 +0100 Subject: [PATCH 22/75] Fixed duplicated symbols for domain initializer. (Thanks to Dominik for reporting the bug.) --- include/react/Domain.h | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/include/react/Domain.h b/include/react/Domain.h index 8bbf6f00..e27c2514 100644 --- a/include/react/Domain.h +++ b/include/react/Domain.h @@ -428,7 +428,16 @@ void AsyncTransaction(TransactionFlagsT flags, TransactionStatus& status, F&& fu #define REACTIVE_DOMAIN(name, ...) \ struct name : \ public REACT_IMPL::DomainBase> {}; \ - REACT_IMPL::DomainInitializer name ## _initializer_; + static REACT_IMPL::DomainInitializer name ## _initializer_; + +/* + A brief reminder why the domain initializer is here: + Each domain has a couple of singletons (debug log, engine, input manager) which are + currently implemented as meyer singletons. From what I understand, these are thread-safe + in C++11, but not all compilers implement that yet. That's why a static initializer has + been added to make sure singleton creation happens before any multi-threaded access. + This implemenation is obviously inconsequential. + */ /////////////////////////////////////////////////////////////////////////////////////////////////// /// Define type aliases for given domain From 412127d0da37f3fafe4d17c07dd51509b737b86e Mon Sep 17 00:00:00 2001 From: schlangster Date: Mon, 12 Jan 2015 17:55:04 +0100 Subject: [PATCH 23/75] Cleanup/refactoring. --- include/react/Event.h | 2 +- include/react/Signal.h | 4 ++-- include/react/TypeTraits.h | 32 ++++++++++++++++++++++---- include/react/detail/graph/GraphBase.h | 6 ++++- tests/src/EventStreamTest.h | 2 +- tests/src/OperationsTest.h | 2 +- 6 files changed, 38 insertions(+), 10 deletions(-) diff --git a/include/react/Event.h b/include/react/Event.h index 777935e9..2c286809 100644 --- a/include/react/Event.h +++ b/include/react/Event.h @@ -348,7 +348,7 @@ auto Transform(const Events& source, const SignalPack& d /// Process /////////////////////////////////////////////////////////////////////////////////////////////////// using REACT_IMPL::EventRange; -using REACT_IMPL::EventInserter; +using REACT_IMPL::EventEmitter; template < diff --git a/include/react/Signal.h b/include/react/Signal.h index 936874b4..7f211392 100644 --- a/include/react/Signal.h +++ b/include/react/Signal.h @@ -933,7 +933,7 @@ bool Equals(const Signal& lhs, const Signal& rhs) REACT_IMPL::Identity::Type::ValueT& r) \ { \ using T = decltype(r.name); \ - using S = REACT_MSVC_NO_TYPENAME REACT::RemoveInput::Type; \ + using S = REACT_MSVC_NO_TYPENAME REACT::DecayInput::Type; \ return static_cast(r.name); \ })) @@ -946,7 +946,7 @@ bool Equals(const Signal& lhs, const Signal& rhs) { \ assert(r != nullptr); \ using T = decltype(r->name); \ - using S = REACT_MSVC_NO_TYPENAME REACT::RemoveInput::Type; \ + using S = REACT_MSVC_NO_TYPENAME REACT::DecayInput::Type; \ return static_cast(r->name); \ })) diff --git a/include/react/TypeTraits.h b/include/react/TypeTraits.h index 7141ac14..c6b6b7dd 100644 --- a/include/react/TypeTraits.h +++ b/include/react/TypeTraits.h @@ -94,6 +94,30 @@ struct IsContinuation { static const bool value = false; }; template struct IsContinuation> { static const bool value = true; }; +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// IsObservable +/////////////////////////////////////////////////////////////////////////////////////////////////// +template +struct IsObservable { static const bool value = false; }; + +template +struct IsObservable> { static const bool value = true; }; + +template +struct IsObservable> { static const bool value = true; }; + +template +struct IsObservable> { static const bool value = true; }; + +template +struct IsObservable> { static const bool value = true; }; + +template +struct IsObservable> { static const bool value = true; }; + +template +struct IsObservable> { static const bool value = true; }; + /////////////////////////////////////////////////////////////////////////////////////////////////// /// IsReactive /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -128,16 +152,16 @@ template struct IsReactive> { static const bool value = true; }; /////////////////////////////////////////////////////////////////////////////////////////////////// -/// RemoveInput +/// DecayInput /////////////////////////////////////////////////////////////////////////////////////////////////// template -struct RemoveInput { using Type = T; }; +struct DecayInput { using Type = T; }; template -struct RemoveInput> { using Type = Signal; }; +struct DecayInput> { using Type = Signal; }; template -struct RemoveInput> { using Type = Events; }; +struct DecayInput> { using Type = Events; }; /******************************************/ REACT_END /******************************************/ diff --git a/include/react/detail/graph/GraphBase.h b/include/react/detail/graph/GraphBase.h index 2adf8160..b7d79d27 100644 --- a/include/react/detail/graph/GraphBase.h +++ b/include/react/detail/graph/GraphBase.h @@ -255,8 +255,12 @@ class EventRange using const_iterator = typename std::vector::const_iterator; using size_type = typename std::vector::size_type; + // Copy ctor EventRange(const EventRange&) = default; + // Copy assignment + EventRange& operator=(const EventRange&) = default; + const_iterator begin() const { return data_.begin(); } const_iterator end() const { return data_.end(); } @@ -272,7 +276,7 @@ class EventRange }; template -using EventInserter = std::back_insert_iterator>; +using EventEmitter = std::back_insert_iterator>; /****************************************/ REACT_IMPL_END /***************************************/ diff --git a/tests/src/EventStreamTest.h b/tests/src/EventStreamTest.h index 39e2479d..bb2efce4 100644 --- a/tests/src/EventStreamTest.h +++ b/tests/src/EventStreamTest.h @@ -285,7 +285,7 @@ TYPED_TEST_P(EventStreamTest, EventProcess) int callCount = 0; auto processed = Process(merged, - [&] (EventRange range, EventInserter out) + [&] (EventRange range, EventEmitter out) { for (const auto& e : range) { diff --git a/tests/src/OperationsTest.h b/tests/src/OperationsTest.h index 77e8c399..5ef9cc3d 100644 --- a/tests/src/OperationsTest.h +++ b/tests/src/OperationsTest.h @@ -911,7 +911,7 @@ TYPED_TEST_P(OperationsTest, SyncedEventProcess1) auto processed = Process(merged, With(mult), - [&] (EventRange range, EventInserter out, int mult) + [&] (EventRange range, EventEmitter out, int mult) { for (const auto& e : range) { From 2f1cb0ac85a3aa4fd8c908832634b85e68aa20fb Mon Sep 17 00:00:00 2001 From: schlangster Date: Mon, 16 Feb 2015 20:12:28 +0100 Subject: [PATCH 24/75] Fixed #8. --- include/react/detail/IReactiveEngine.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/react/detail/IReactiveEngine.h b/include/react/detail/IReactiveEngine.h index 33aaf076..9a422cb8 100644 --- a/include/react/detail/IReactiveEngine.h +++ b/include/react/detail/IReactiveEngine.h @@ -72,7 +72,7 @@ struct EngineInterface static void OnTurnAdmissionStart(TurnT& turn) { - Instance().OnTurnAdmissionEnd(turn); + Instance().OnTurnAdmissionStart(turn); } static void OnTurnAdmissionEnd(TurnT& turn) From 1f6ddb75ccba2304d7fdfeb36e398fc276d7b89b Mon Sep 17 00:00:00 2001 From: schlangster Date: Mon, 23 Mar 2015 11:44:12 +0100 Subject: [PATCH 25/75] Fixed #9 --- include/react/common/Timing.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/include/react/common/Timing.h b/include/react/common/Timing.h index 08f72892..3775661d 100644 --- a/include/react/common/Timing.h +++ b/include/react/common/Timing.h @@ -189,7 +189,11 @@ class ConditionalTimer private: // Only measure once bool shouldMeasure_ = true; - bool isThresholdExceeded_ = false; + + // Until we have measured, assume the threshold is exceeded. + // The cost of initially not parallelizing what should be parallelized is much higher + // than for the other way around. + bool isThresholdExceeded_ = true; }; /****************************************/ REACT_IMPL_END /***************************************/ From 0ca831161895a04d7965144ddc35d16f3b3c1f24 Mon Sep 17 00:00:00 2001 From: schlangster Date: Sun, 12 Jun 2016 15:23:43 +0200 Subject: [PATCH 26/75] Update to VS2015. --- project/msvc/CppReact.vcxproj | 10 +++++----- project/msvc/CppReactBenchmark.vcxproj | 10 +++++----- project/msvc/CppReactExample.vcxproj | 10 +++++----- project/msvc/CppReactTest.vcxproj | 10 +++++----- project/msvc/Example_BasicAlgorithms.vcxproj | 10 +++++----- project/msvc/Example_BasicComposition.vcxproj | 10 +++++----- project/msvc/Example_BasicEvents.vcxproj | 10 +++++----- project/msvc/Example_BasicObservers.vcxproj | 10 +++++----- project/msvc/Example_BasicReactors.vcxproj | 10 +++++----- project/msvc/Example_BasicSignals.vcxproj | 10 +++++----- project/msvc/Example_BasicSynchronization.vcxproj | 10 +++++----- 11 files changed, 55 insertions(+), 55 deletions(-) diff --git a/project/msvc/CppReact.vcxproj b/project/msvc/CppReact.vcxproj index 16ae1f97..d9782c0d 100644 --- a/project/msvc/CppReact.vcxproj +++ b/project/msvc/CppReact.vcxproj @@ -1,5 +1,5 @@  - + Debug @@ -26,26 +26,26 @@ StaticLibrary true - v120 + v140 MultiByte StaticLibrary true - v120 + v140 MultiByte StaticLibrary false - v120 + v140 true MultiByte StaticLibrary false - v120 + v140 true MultiByte diff --git a/project/msvc/CppReactBenchmark.vcxproj b/project/msvc/CppReactBenchmark.vcxproj index 7613239a..a57e4b20 100644 --- a/project/msvc/CppReactBenchmark.vcxproj +++ b/project/msvc/CppReactBenchmark.vcxproj @@ -1,5 +1,5 @@  - + Debug @@ -26,26 +26,26 @@ Application true - v120 + v140 MultiByte Application true - v120 + v140 MultiByte Application false - v120 + v140 true MultiByte Application false - v120 + v140 true MultiByte diff --git a/project/msvc/CppReactExample.vcxproj b/project/msvc/CppReactExample.vcxproj index 323c777f..34a714e6 100644 --- a/project/msvc/CppReactExample.vcxproj +++ b/project/msvc/CppReactExample.vcxproj @@ -1,5 +1,5 @@  - + Debug @@ -27,26 +27,26 @@ Application true - v120 + v140 MultiByte Application true - v120 + v140 MultiByte Application false - v120 + v140 true MultiByte Application false - v120 + v140 true MultiByte diff --git a/project/msvc/CppReactTest.vcxproj b/project/msvc/CppReactTest.vcxproj index 7b1cb65f..5c2878a4 100644 --- a/project/msvc/CppReactTest.vcxproj +++ b/project/msvc/CppReactTest.vcxproj @@ -1,5 +1,5 @@  - + Debug @@ -26,26 +26,26 @@ Application true - v120 + v140 MultiByte Application true - v120 + v140 MultiByte Application false - v120 + v140 true MultiByte Application false - v120 + v140 true MultiByte diff --git a/project/msvc/Example_BasicAlgorithms.vcxproj b/project/msvc/Example_BasicAlgorithms.vcxproj index eeffca5a..f77233e6 100644 --- a/project/msvc/Example_BasicAlgorithms.vcxproj +++ b/project/msvc/Example_BasicAlgorithms.vcxproj @@ -1,5 +1,5 @@  - + Debug @@ -26,26 +26,26 @@ Application true - v120 + v140 MultiByte Application true - v120 + v140 MultiByte Application false - v120 + v140 true MultiByte Application false - v120 + v140 true MultiByte diff --git a/project/msvc/Example_BasicComposition.vcxproj b/project/msvc/Example_BasicComposition.vcxproj index 01d26c88..43101fb2 100644 --- a/project/msvc/Example_BasicComposition.vcxproj +++ b/project/msvc/Example_BasicComposition.vcxproj @@ -1,5 +1,5 @@  - + Debug @@ -26,26 +26,26 @@ Application true - v120 + v140 MultiByte Application true - v120 + v140 MultiByte Application false - v120 + v140 true MultiByte Application false - v120 + v140 true MultiByte diff --git a/project/msvc/Example_BasicEvents.vcxproj b/project/msvc/Example_BasicEvents.vcxproj index d5d13295..07370926 100644 --- a/project/msvc/Example_BasicEvents.vcxproj +++ b/project/msvc/Example_BasicEvents.vcxproj @@ -1,5 +1,5 @@  - + Debug @@ -26,26 +26,26 @@ Application true - v120 + v140 MultiByte Application true - v120 + v140 MultiByte Application false - v120 + v140 true MultiByte Application false - v120 + v140 true MultiByte diff --git a/project/msvc/Example_BasicObservers.vcxproj b/project/msvc/Example_BasicObservers.vcxproj index 9fa37b8c..7e27da42 100644 --- a/project/msvc/Example_BasicObservers.vcxproj +++ b/project/msvc/Example_BasicObservers.vcxproj @@ -1,5 +1,5 @@  - + Debug @@ -26,26 +26,26 @@ Application true - v120 + v140 MultiByte Application true - v120 + v140 MultiByte Application false - v120 + v140 true MultiByte Application false - v120 + v140 true MultiByte diff --git a/project/msvc/Example_BasicReactors.vcxproj b/project/msvc/Example_BasicReactors.vcxproj index 07701d98..ba7b1dad 100644 --- a/project/msvc/Example_BasicReactors.vcxproj +++ b/project/msvc/Example_BasicReactors.vcxproj @@ -1,5 +1,5 @@  - + Debug @@ -26,26 +26,26 @@ Application true - v120 + v140 MultiByte Application true - v120 + v140 MultiByte Application false - v120 + v140 true MultiByte Application false - v120 + v140 true MultiByte diff --git a/project/msvc/Example_BasicSignals.vcxproj b/project/msvc/Example_BasicSignals.vcxproj index e090dd8a..556b2ad0 100644 --- a/project/msvc/Example_BasicSignals.vcxproj +++ b/project/msvc/Example_BasicSignals.vcxproj @@ -1,5 +1,5 @@  - + Debug @@ -26,26 +26,26 @@ Application true - v120 + v140 MultiByte Application true - v120 + v140 MultiByte Application false - v120 + v140 true MultiByte Application false - v120 + v140 true MultiByte diff --git a/project/msvc/Example_BasicSynchronization.vcxproj b/project/msvc/Example_BasicSynchronization.vcxproj index 2b2edec4..faa0ccfb 100644 --- a/project/msvc/Example_BasicSynchronization.vcxproj +++ b/project/msvc/Example_BasicSynchronization.vcxproj @@ -1,5 +1,5 @@  - + Debug @@ -26,26 +26,26 @@ Application true - v120 + v140 MultiByte Application true - v120 + v140 MultiByte Application false - v120 + v140 true MultiByte Application false - v120 + v140 true MultiByte From 872d6d34a5eacac966ac5bb1058f05c0d4d5e0ec Mon Sep 17 00:00:00 2001 From: schlangster Date: Sun, 12 Jun 2016 15:24:33 +0200 Subject: [PATCH 27/75] WIP refactor --- benchmarks/src/Main.cpp | 15 +- include/react/Event.h | 495 ++--------------- include/react/Observer.h | 8 +- include/react/Signal.h | 652 +---------------------- include/react/TypeTraits.h | 113 ++-- include/react/detail/graph/SignalNodes.h | 39 +- 6 files changed, 135 insertions(+), 1187 deletions(-) diff --git a/benchmarks/src/Main.cpp b/benchmarks/src/Main.cpp index eb47f33f..00284776 100644 --- a/benchmarks/src/Main.cpp +++ b/benchmarks/src/Main.cpp @@ -37,6 +37,11 @@ REACTIVE_DOMAIN(ToposortDomain, parallel, ToposortEngine) REACTIVE_DOMAIN(PulsecountDomain, parallel, PulsecountEngine) REACTIVE_DOMAIN(SubtreeDomain, parallel, SubtreeEngine) +REACTIVE_DOMAIN(ToposortSTDomainConc, sequential_concurrent, ToposortEngine) +REACTIVE_DOMAIN(ToposortDomainConc, parallel_concurrent, ToposortEngine) +REACTIVE_DOMAIN(PulsecountDomainConc, parallel_concurrent, PulsecountEngine) +REACTIVE_DOMAIN(SubtreeDomainConc, parallel_concurrent, SubtreeEngine) + void runBenchmarkGrid(std::ostream& out) { RUN_BENCHMARK(out, 5, Benchmark_Grid, BenchmarkParams_Grid(20, 10000), @@ -130,7 +135,7 @@ void runBenchmarkLifeSim(std::ostream& out) // SourceSetDomain, PulsecountDomain); RUN_BENCHMARK(out, 1, Benchmark_LifeSim, BenchmarkParams_LifeSim(100, 15, 10000), - ToposortSTDomain, ToposortDomain, PulsecountDomain); + ToposortSTDomainConc, ToposortDomainConc, PulsecountDomainConc); //RUN_BENCHMARK(out, 3, Benchmark_LifeSim, BenchmarkParams_LifeSim(100, 50, 100), // PulsecountDomain, PulsecountDomain); @@ -216,9 +221,9 @@ void debugBenchmarks() void profileBenchmark() { - RUN_BENCHMARK(std::cout, 1, Benchmark_Grid, BenchmarkParams_Grid(30, 10000), - ToposortSTDomain); - //ToposortSTDomain, ToposortDomain, PulsecountDomain, SubtreeDomain); + RUN_BENCHMARK(std::cout, 3, Benchmark_Grid, BenchmarkParams_Grid(100, 10000), + //SubtreeDomain); + ToposortSTDomain, ToposortDomain, PulsecountDomain, SubtreeDomain); //RUN_BENCHMARK(std::cout, 1, Benchmark_Grid, BenchmarkParams_Grid(30, 10000), //SourceSetDomain); @@ -228,7 +233,7 @@ void profileBenchmark() //ToposortSTDomain, ToposortDomain, PulsecountDomain, SubtreeDomain); //RUN_BENCHMARK(std::cout, 1, Benchmark_LifeSim, BenchmarkParams_LifeSim(100, 15, 10000), - //ToposortSTDomain); + //ToposortSTDomainConc); } } // ~anonymous namespace diff --git a/include/react/Event.h b/include/react/Event.h index 2c286809..8ca754c2 100644 --- a/include/react/Event.h +++ b/include/react/Event.h @@ -25,36 +25,28 @@ /////////////////////////////////////////////////////////////////////////////////////////////////// /// Forward declarations /////////////////////////////////////////////////////////////////////////////////////////////////// -template +template class Events; -template +template class EventSource; -template -class TempEvents; - enum class Token; -template +template class Signal; -template -class SignalPack; - using REACT_IMPL::WeightHint; /////////////////////////////////////////////////////////////////////////////////////////////////// /// MakeEventSource /////////////////////////////////////////////////////////////////////////////////////////////////// -template -auto MakeEventSource() - -> EventSource +template +auto MakeEventSource() -> EventSource { using REACT_IMPL::EventSourceNode; - return EventSource( - std::make_shared>()); + return EventSource(std::make_shared>()); } /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -62,174 +54,49 @@ auto MakeEventSource() /////////////////////////////////////////////////////////////////////////////////////////////////// template < - typename D, typename TArg1, typename ... TArgs, - typename E = TArg1, - typename TOp = REACT_IMPL::EventMergeOp, - REACT_IMPL::EventStreamNodePtrT ...> + typename E = TArg1 > -auto Merge(const Events& arg1, const Events& ... args) - -> TempEvents +auto Merge(const Events& arg1, const Events& ... args) -> Events { using REACT_IMPL::EventOpNode; - static_assert(sizeof...(TArgs) > 0, - "Merge: 2+ arguments are required."); + static_assert(sizeof...(TArgs) > 0, "Merge: 2+ arguments are required."); - return TempEvents( - std::make_shared>( + return Events( + std::make_shared>( GetNodePtr(arg1), GetNodePtr(args) ...)); } -template -< - typename TLeftEvents, - typename TRightEvents, - typename D = typename TLeftEvents::DomainT, - typename TLeftVal = typename TLeftEvents::ValueT, - typename TRightVal = typename TRightEvents::ValueT, - typename E = TLeftVal, - typename TOp = REACT_IMPL::EventMergeOp, - REACT_IMPL::EventStreamNodePtrT>, - class = typename std::enable_if< - IsEvent::value>::type, - class = typename std::enable_if< - IsEvent::value>::type -> -auto operator|(const TLeftEvents& lhs, const TRightEvents& rhs) - -> TempEvents -{ - using REACT_IMPL::EventOpNode; - - return TempEvents( - std::make_shared>( - GetNodePtr(lhs), GetNodePtr(rhs))); -} - -template -< - typename D, - typename TLeftVal, - typename TLeftOp, - typename TRightVal, - typename TRightOp, - typename E = TLeftVal, - typename TOp = REACT_IMPL::EventMergeOp -> -auto operator|(TempEvents&& lhs, TempEvents&& rhs) - -> TempEvents -{ - using REACT_IMPL::EventOpNode; - - return TempEvents( - std::make_shared>( - lhs.StealOp(), rhs.StealOp())); -} - -template -< - typename D, - typename TLeftVal, - typename TLeftOp, - typename TRightEvents, - typename TRightVal = typename TRightEvents::ValueT, - typename E = TLeftVal, - typename TOp = REACT_IMPL::EventMergeOp>, - class = typename std::enable_if< - IsEvent::value>::type -> -auto operator|(TempEvents&& lhs, const TRightEvents& rhs) - -> TempEvents -{ - using REACT_IMPL::EventOpNode; - - return TempEvents( - std::make_shared>( - lhs.StealOp(), GetNodePtr(rhs))); -} - -template -< - typename TLeftEvents, - typename D, - typename TRightVal, - typename TRightOp, - typename TLeftVal = typename TLeftEvents::ValueT, - typename E = TLeftVal, - typename TOp = REACT_IMPL::EventMergeOp, - TRightOp>, - class = typename std::enable_if< - IsEvent::value>::type -> -auto operator|(const TLeftEvents& lhs, TempEvents&& rhs) - -> TempEvents -{ - using REACT_IMPL::EventOpNode; - - return TempEvents( - std::make_shared>( - GetNodePtr(lhs), rhs.StealOp())); -} - /////////////////////////////////////////////////////////////////////////////////////////////////// /// Filter /////////////////////////////////////////////////////////////////////////////////////////////////// template < - typename D, typename E, typename FIn, - typename F = typename std::decay::type, - typename TOp = REACT_IMPL::EventFilterOp> + typename F = typename std::decay::type > -auto Filter(const Events& src, FIn&& filter) - -> TempEvents +auto Filter(const Events& src, FIn&& filter) -> Events { using REACT_IMPL::EventOpNode; - return TempEvents( - std::make_shared>( + return Events( + std::make_shared>( std::forward(filter), GetNodePtr(src))); } -template -< - typename D, - typename E, - typename TOpIn, - typename FIn, - typename F = typename std::decay::type, - typename TOpOut = REACT_IMPL::EventFilterOp -> -auto Filter(TempEvents&& src, FIn&& filter) - -> TempEvents -{ - using REACT_IMPL::EventOpNode; - - return TempEvents( - std::make_shared>( - std::forward(filter), src.StealOp())); -} - /////////////////////////////////////////////////////////////////////////////////////////////////// /// Filter - Synced /////////////////////////////////////////////////////////////////////////////////////////////////// template < - typename D, typename E, typename FIn, typename ... TDepValues > -auto Filter(const Events& source, const SignalPack& depPack, FIn&& func) - -> Events +auto Filter(const Events& source, const SignalPack& depPack, FIn&& func) -> Events { using REACT_IMPL::SyncedEventFilterNode; @@ -237,20 +104,20 @@ auto Filter(const Events& source, const SignalPack& depPac struct NodeBuilder_ { - NodeBuilder_(const Events& source, FIn&& func) : + NodeBuilder_(const Events& source, FIn&& func) : MySource( source ), MyFunc( std::forward(func) ) {} auto operator()(const Signal& ... deps) - -> Events + -> Events { - return Events( + return Events( std::make_shared>( GetNodePtr(MySource), std::forward(MyFunc), GetNodePtr(deps) ...)); } - const Events& MySource; + const Events& MySource; FIn MyFunc; }; @@ -264,57 +131,31 @@ auto Filter(const Events& source, const SignalPack& depPac /////////////////////////////////////////////////////////////////////////////////////////////////// template < - typename D, typename TIn, typename FIn, typename F = typename std::decay::type, - typename TOut = typename std::result_of::type, - typename TOp = REACT_IMPL::EventTransformOp> + typename TOut = typename std::result_of::type > -auto Transform(const Events& src, FIn&& func) - -> TempEvents +auto Transform(const Events& src, FIn&& func) -> Events { using REACT_IMPL::EventOpNode; - return TempEvents( - std::make_shared>( + return Events( + std::make_shared>( std::forward(func), GetNodePtr(src))); } -template -< - typename D, - typename TIn, - typename TOpIn, - typename FIn, - typename F = typename std::decay::type, - typename TOut = typename std::result_of::type, - typename TOpOut = REACT_IMPL::EventTransformOp -> -auto Transform(TempEvents&& src, FIn&& func) - -> TempEvents -{ - using REACT_IMPL::EventOpNode; - - return TempEvents( - std::make_shared>( - std::forward(func), src.StealOp())); -} - /////////////////////////////////////////////////////////////////////////////////////////////////// /// Transform - Synced /////////////////////////////////////////////////////////////////////////////////////////////////// template < - typename D, typename TIn, typename FIn, typename ... TDepValues, typename TOut = typename std::result_of::type > -auto Transform(const Events& source, const SignalPack& depPack, FIn&& func) - -> Events +auto Transform(const Events& source, FIn&& func, const Signal& ... deps) -> Events { using REACT_IMPL::SyncedEventTransformNode; @@ -322,20 +163,20 @@ auto Transform(const Events& source, const SignalPack& d struct NodeBuilder_ { - NodeBuilder_(const Events& source, FIn&& func) : + NodeBuilder_(const Events& source, FIn&& func) : MySource( source ), MyFunc( std::forward(func) ) {} auto operator()(const Signal& ... deps) - -> Events + -> Events { - return Events( + return Events( std::make_shared>( GetNodePtr(MySource), std::forward(MyFunc), GetNodePtr(deps) ...)); } - const Events& MySource; + const Events& MySource; FIn MyFunc; }; @@ -353,17 +194,15 @@ using REACT_IMPL::EventEmitter; template < typename TOut, - typename D, typename TIn, typename FIn, typename F = typename std::decay::type > -auto Process(const Events& src, FIn&& func) - -> Events +auto Process(const Events& src, FIn&& func) -> Events { using REACT_IMPL::EventProcessingNode; - return Events( + return Events( std::make_shared>( GetNodePtr(src), std::forward(func))); } @@ -374,13 +213,11 @@ auto Process(const Events& src, FIn&& func) template < typename TOut, - typename D, typename TIn, typename FIn, typename ... TDepValues > -auto Process(const Events& source, const SignalPack& depPack, FIn&& func) - -> Events +auto Process(const Events& source, const SignalPack& depPack, FIn&& func) -> Events { using REACT_IMPL::SyncedEventProcessingNode; @@ -388,20 +225,20 @@ auto Process(const Events& source, const SignalPack& dep struct NodeBuilder_ { - NodeBuilder_(const Events& source, FIn&& func) : + NodeBuilder_(const Events& source, FIn&& func) : MySource( source ), MyFunc( std::forward(func) ) {} auto operator()(const Signal& ... deps) - -> Events + -> Events { - return Events( + return Events( std::make_shared>( GetNodePtr(MySource), std::forward(MyFunc), GetNodePtr(deps) ...)); } - const Events& MySource; + const Events& MySource; FIn MyFunc; }; @@ -413,37 +250,26 @@ auto Process(const Events& source, const SignalPack& dep /////////////////////////////////////////////////////////////////////////////////////////////////// /// Flatten /////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename D, - typename TInnerValue -> -auto Flatten(const Signal>& outer) - -> Events +template +auto Flatten(const Signal>& outer) -> Events { - return Events( - std::make_shared, TInnerValue>>( + return Events( + std::make_shared, TInnerValue>>( GetNodePtr(outer), GetNodePtr(outer.Value()))); } /////////////////////////////////////////////////////////////////////////////////////////////////// /// Join /////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename D, - typename ... TArgs -> -auto Join(const Events& ... args) - -> Events> +template +auto Join(const Events& ... args) -> Events> { using REACT_IMPL::EventJoinNode; - static_assert(sizeof...(TArgs) > 1, - "Join: 2+ arguments are required."); + static_assert(sizeof...(TArgs) > 1, "Join: 2+ arguments are required."); - return Events>( - std::make_shared>( + return Events< std::tuple>( + std::make_shared>( GetNodePtr(args) ...)); } @@ -459,8 +285,7 @@ struct Tokenizer }; template -auto Tokenize(TEvents&& source) - -> decltype(Transform(source, Tokenizer{})) +auto Tokenize(TEvents&& source) -> decltype(Transform(source, Tokenizer{})) { return Transform(source, Tokenizer{}); } @@ -468,15 +293,11 @@ auto Tokenize(TEvents&& source) /////////////////////////////////////////////////////////////////////////////////////////////////// /// Events /////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename D, - typename E = Token -> -class Events : public REACT_IMPL::EventStreamBase +template +class Events : public REACT_IMPL::EventStreamBase { private: - using NodeT = REACT_IMPL::EventStreamNode; + using NodeT = REACT_IMPL::EventStreamNode; using NodePtrT = std::shared_ptr; public: @@ -551,99 +372,11 @@ class Events : public REACT_IMPL::EventStreamBase } }; -// Specialize for references -template -< - typename D, - typename E -> -class Events : public REACT_IMPL::EventStreamBase> -{ -private: - using NodeT = REACT_IMPL::EventStreamNode>; - using NodePtrT = std::shared_ptr; - -public: - using ValueT = E; - - // Default ctor - Events() = default; - - // Copy ctor - Events(const Events&) = default; - - // Move ctor - Events(Events&& other) : - Events::EventStreamBase( std::move(other) ) - {} - - // Node ctor - explicit Events(NodePtrT&& nodePtr) : - Events::EventStreamBase( std::move(nodePtr) ) - {} - - // Copy assignment - Events& operator=(const Events&) = default; - - // Move assignment - Events& operator=(Events&& other) - { - Events::EventStreamBase::operator=( std::move(other) ); - return *this; - } - - bool Equals(const Events& other) const - { - return Events::EventStreamBase::Equals(other); - } - - bool IsValid() const - { - return Events::EventStreamBase::IsValid(); - } - - void SetWeightHint(WeightHint weight) - { - Events::EventStreamBase::SetWeightHint(weight); - } - - auto Tokenize() const - -> decltype(REACT::Tokenize(std::declval())) - { - return REACT::Tokenize(*this); - } - - template - auto Merge(TArgs&& ... args) - -> decltype(REACT::Merge(std::declval(), std::forward(args) ...)) - { - return REACT::Merge(*this, std::forward(args) ...); - } - - template - auto Filter(F&& f) const - -> decltype(REACT::Filter(std::declval(), std::forward(f))) - { - return REACT::Filter(*this, std::forward(f)); - } - - template - auto Transform(F&& f) const - -> decltype(REACT::Transform(std::declval(), std::forward(f))) - { - return REACT::Transform(*this, std::forward(f)); - } -}; - /////////////////////////////////////////////////////////////////////////////////////////////////// /// EventSource /////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename D, - typename E = Token -> -class EventSource : public Events +template +class EventSource : public Events { private: using NodeT = REACT_IMPL::EventSourceNode; @@ -710,134 +443,12 @@ class EventSource : public Events } }; -// Specialize for references -template -< - typename D, - typename E -> -class EventSource : public Events> -{ -private: - using NodeT = REACT_IMPL::EventSourceNode>; - using NodePtrT = std::shared_ptr; - -public: - // Default ctor - EventSource() = default; - - // Copy ctor - EventSource(const EventSource&) = default; - - // Move ctor - EventSource(EventSource&& other) : - EventSource::Events( std::move(other) ) - {} - - // Node ctor - explicit EventSource(NodePtrT&& nodePtr) : - EventSource::Events( std::move(nodePtr) ) - {} - - // Copy assignment - EventSource& operator=(const EventSource&) = default; - - // Move assignment - EventSource& operator=(EventSource&& other) - { - EventSource::Events::operator=( std::move(other) ); - return *this; - } - - // Explicit emit - void Emit(std::reference_wrapper e) const { EventSource::EventStreamBase::emit(e); } - - // Function object style - void operator()(std::reference_wrapper e) const { EventSource::EventStreamBase::emit(e); } - - // Stream style - const EventSource& operator<<(std::reference_wrapper e) const - { - EventSource::EventStreamBase::emit(e); - return *this; - } -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// TempEvents -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename D, - typename E, - typename TOp -> -class TempEvents : public Events -{ -protected: - using NodeT = REACT_IMPL::EventOpNode; - using NodePtrT = std::shared_ptr; - -public: - // Default ctor - TempEvents() = default; - - // Copy ctor - TempEvents(const TempEvents&) = default; - - // Move ctor - TempEvents(TempEvents&& other) : - TempEvents::Events( std::move(other) ) - {} - - // Node ctor - explicit TempEvents(NodePtrT&& nodePtr) : - TempEvents::Events( std::move(nodePtr) ) - {} - - // Copy assignment - TempEvents& operator=(const TempEvents&) = default; - - // Move assignment - TempEvents& operator=(TempEvents&& other) - { - TempEvents::EventStreamBase::operator=( std::move(other) ); - return *this; - } - - TOp StealOp() - { - return std::move(reinterpret_cast(this->ptr_.get())->StealOp()); - } - - template - auto Merge(TArgs&& ... args) - -> decltype(REACT::Merge(std::declval(), std::forward(args) ...)) - { - return REACT::Merge(*this, std::forward(args) ...); - } - - template - auto Filter(F&& f) const - -> decltype(REACT::Filter(std::declval(), std::forward(f))) - { - return REACT::Filter(*this, std::forward(f)); - } - - template - auto Transform(F&& f) const - -> decltype(REACT::Transform(std::declval(), std::forward(f))) - { - return REACT::Transform(*this, std::forward(f)); - } -}; - /******************************************/ REACT_END /******************************************/ /***************************************/ REACT_IMPL_BEGIN /**************************************/ -template -bool Equals(const Events& lhs, const Events& rhs) +template +bool Equals(const Events& lhs, const Events& rhs) { return lhs.Equals(rhs); } diff --git a/include/react/Observer.h b/include/react/Observer.h index 45fd78a1..c9d986dc 100644 --- a/include/react/Observer.h +++ b/include/react/Observer.h @@ -24,13 +24,10 @@ /////////////////////////////////////////////////////////////////////////////////////////////////// /// Forward declarations /////////////////////////////////////////////////////////////////////////////////////////////////// -template +template class Signal; -template -class SignalPack; - -template +template class Events; using REACT_IMPL::ObserverAction; @@ -39,7 +36,6 @@ using REACT_IMPL::WeightHint; /////////////////////////////////////////////////////////////////////////////////////////////////// /// Observer /////////////////////////////////////////////////////////////////////////////////////////////////// -template class Observer { private: diff --git a/include/react/Signal.h b/include/react/Signal.h index 7f211392..ac5c6030 100644 --- a/include/react/Signal.h +++ b/include/react/Signal.h @@ -29,83 +29,34 @@ /////////////////////////////////////////////////////////////////////////////////////////////////// /// Forward declarations /////////////////////////////////////////////////////////////////////////////////////////////////// -template +template class Signal; -template +template class VarSignal; -template -class TempSignal; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// SignalPack - Wraps several nodes in a tuple. Create with comma operator. -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename D, - typename ... TValues -> -class SignalPack -{ -public: - SignalPack(const Signal& ... deps) : - Data( std::tie(deps ...) ) - {} - - template - SignalPack(const SignalPack& curArgs, const Signal& newArg) : - Data( std::tuple_cat(curArgs.Data, std::tie(newArg)) ) - {} - - std::tuple& ...> Data; -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// With - Utility function to create a SignalPack -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename D, - typename ... TValues -> -auto With(const Signal& ... deps) - -> SignalPack -{ - return SignalPack(deps ...); -} - /////////////////////////////////////////////////////////////////////////////////////////////////// /// MakeVar /////////////////////////////////////////////////////////////////////////////////////////////////// template < - typename D, typename V, typename S = typename std::decay::type, - class = typename std::enable_if< - ! IsSignal::value>::type, - class = typename std::enable_if< - ! IsEvent::value>::type + class = typename std::enable_if::value>::type, + class = typename std::enable_if::value>::type > -auto MakeVar(V&& value) - -> VarSignal +auto MakeVar(V&& value) -> VarSignal { - return VarSignal( - std::make_shared>( + return VarSignal( + std::make_shared>( std::forward(value))); } -template -< - typename D, - typename S -> -auto MakeVar(std::reference_wrapper value) - -> VarSignal +template +auto MakeVar(std::reference_wrapper value) -> VarSignal { - return VarSignal( - std::make_shared>>(value)); + return VarSignal( + std::make_shared>>(value)); } /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -113,15 +64,13 @@ auto MakeVar(std::reference_wrapper value) /////////////////////////////////////////////////////////////////////////////////////////////////// template < - typename D, typename V, typename S = typename std::decay::type, typename TInner = typename S::ValueT, - class = typename std::enable_if< - IsSignal::value>::type + class = typename std::enable_if::value>::type > auto MakeVar(V&& value) - -> VarSignal> + -> VarSignal> { return VarSignal>( std::make_shared>>( @@ -130,7 +79,7 @@ auto MakeVar(V&& value) template < - typename D, + typename V, typename S = typename std::decay::type, typename TInner = typename S::ValueT, @@ -151,7 +100,7 @@ auto MakeVar(V&& value) // Single arg template < - typename D, + typename TValue, typename FIn, typename F = typename std::decay::type, @@ -169,7 +118,7 @@ auto MakeSignal(const Signal& arg, FIn&& func) // Multiple args template < - typename D, + typename ... TValues, typename FIn, typename F = typename std::decay::type, @@ -203,396 +152,10 @@ auto MakeSignal(const SignalPack& argPack, FIn&& func) argPack.Data); } -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Unary operators -/////////////////////////////////////////////////////////////////////////////////////////////////// -#define REACT_DECLARE_OP(op,name) \ -template \ -struct name ## OpFunctor \ -{ \ - T operator()(const T& v) const { return op v; } \ -}; \ - \ -template \ -< \ - typename TSignal, \ - typename D = typename TSignal::DomainT, \ - typename TVal = typename TSignal::ValueT, \ - class = typename std::enable_if< \ - IsSignal::value>::type, \ - typename F = name ## OpFunctor, \ - typename S = typename std::result_of::type, \ - typename TOp = REACT_IMPL::FunctionOp> \ -> \ -auto operator op(const TSignal& arg) \ - -> TempSignal \ -{ \ - return TempSignal( \ - std::make_shared>( \ - F(), GetNodePtr(arg))); \ -} \ - \ -template \ -< \ - typename D, \ - typename TVal, \ - typename TOpIn, \ - typename F = name ## OpFunctor, \ - typename S = typename std::result_of::type, \ - typename TOp = REACT_IMPL::FunctionOp \ -> \ -auto operator op(TempSignal&& arg) \ - -> TempSignal \ -{ \ - return TempSignal( \ - std::make_shared>( \ - F(), arg.StealOp())); \ -} - -REACT_DECLARE_OP(+, UnaryPlus) -REACT_DECLARE_OP(-, UnaryMinus) -REACT_DECLARE_OP(!, LogicalNegation) -REACT_DECLARE_OP(~, BitwiseComplement) -REACT_DECLARE_OP(++, Increment) -REACT_DECLARE_OP(--, Decrement) - -#undef REACT_DECLARE_OP - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Binary operators -/////////////////////////////////////////////////////////////////////////////////////////////////// -#define REACT_DECLARE_OP(op,name) \ -template \ -struct name ## OpFunctor \ -{ \ - auto operator()(const L& lhs, const R& rhs) const \ - -> decltype(std::declval() op std::declval()) \ - { \ - return lhs op rhs; \ - } \ -}; \ - \ -template \ -struct name ## OpRFunctor \ -{ \ - name ## OpRFunctor(name ## OpRFunctor&& other) : \ - LeftVal( std::move(other.LeftVal) ) \ - {} \ - \ - template \ - name ## OpRFunctor(T&& val) : \ - LeftVal( std::forward(val) ) \ - {} \ - \ - name ## OpRFunctor(const name ## OpRFunctor& other) = delete; \ - \ - auto operator()(const R& rhs) const \ - -> decltype(std::declval() op std::declval()) \ - { \ - return LeftVal op rhs; \ - } \ - \ - L LeftVal; \ -}; \ - \ -template \ -struct name ## OpLFunctor \ -{ \ - name ## OpLFunctor(name ## OpLFunctor&& other) : \ - RightVal( std::move(other.RightVal) ) \ - {} \ - \ - template \ - name ## OpLFunctor(T&& val) : \ - RightVal( std::forward(val) ) \ - {} \ - \ - name ## OpLFunctor(const name ## OpLFunctor& other) = delete; \ - \ - auto operator()(const L& lhs) const \ - -> decltype(std::declval() op std::declval()) \ - { \ - return lhs op RightVal; \ - } \ - \ - R RightVal; \ -}; \ - \ -template \ -< \ - typename TLeftSignal, \ - typename TRightSignal, \ - typename D = typename TLeftSignal::DomainT, \ - typename TLeftVal = typename TLeftSignal::ValueT, \ - typename TRightVal = typename TRightSignal::ValueT, \ - class = typename std::enable_if< \ - IsSignal::value>::type, \ - class = typename std::enable_if< \ - IsSignal::value>::type, \ - typename F = name ## OpFunctor, \ - typename S = typename std::result_of::type, \ - typename TOp = REACT_IMPL::FunctionOp, \ - REACT_IMPL::SignalNodePtrT> \ -> \ -auto operator op(const TLeftSignal& lhs, const TRightSignal& rhs) \ - -> TempSignal \ -{ \ - return TempSignal( \ - std::make_shared>( \ - F(), GetNodePtr(lhs), GetNodePtr(rhs))); \ -} \ - \ -template \ -< \ - typename TLeftSignal, \ - typename TRightValIn, \ - typename D = typename TLeftSignal::DomainT, \ - typename TLeftVal = typename TLeftSignal::ValueT, \ - typename TRightVal = typename std::decay::type, \ - class = typename std::enable_if< \ - IsSignal::value>::type, \ - class = typename std::enable_if< \ - ! IsSignal::value>::type, \ - typename F = name ## OpLFunctor, \ - typename S = typename std::result_of::type, \ - typename TOp = REACT_IMPL::FunctionOp> \ -> \ -auto operator op(const TLeftSignal& lhs, TRightValIn&& rhs) \ - -> TempSignal \ -{ \ - return TempSignal( \ - std::make_shared>( \ - F( std::forward(rhs) ), GetNodePtr(lhs))); \ -} \ - \ -template \ -< \ - typename TLeftValIn, \ - typename TRightSignal, \ - typename D = typename TRightSignal::DomainT, \ - typename TLeftVal = typename std::decay::type, \ - typename TRightVal = typename TRightSignal::ValueT, \ - class = typename std::enable_if< \ - ! IsSignal::value>::type, \ - class = typename std::enable_if< \ - IsSignal::value>::type, \ - typename F = name ## OpRFunctor, \ - typename S = typename std::result_of::type, \ - typename TOp = REACT_IMPL::FunctionOp> \ -> \ -auto operator op(TLeftValIn&& lhs, const TRightSignal& rhs) \ - -> TempSignal \ -{ \ - return TempSignal( \ - std::make_shared>( \ - F( std::forward(lhs) ), GetNodePtr(rhs))); \ -} \ -template \ -< \ - typename D, \ - typename TLeftVal, \ - typename TLeftOp, \ - typename TRightVal, \ - typename TRightOp, \ - typename F = name ## OpFunctor, \ - typename S = typename std::result_of::type, \ - typename TOp = REACT_IMPL::FunctionOp \ -> \ -auto operator op(TempSignal&& lhs, \ - TempSignal&& rhs) \ - -> TempSignal \ -{ \ - return TempSignal( \ - std::make_shared>( \ - F(), lhs.StealOp(), rhs.StealOp())); \ -} \ - \ -template \ -< \ - typename D, \ - typename TLeftVal, \ - typename TLeftOp, \ - typename TRightSignal, \ - typename TRightVal = typename TRightSignal::ValueT, \ - class = typename std::enable_if< \ - IsSignal::value>::type, \ - typename F = name ## OpFunctor, \ - typename S = typename std::result_of::type, \ - typename TOp = REACT_IMPL::FunctionOp> \ -> \ -auto operator op(TempSignal&& lhs, \ - const TRightSignal& rhs) \ - -> TempSignal \ -{ \ - return TempSignal( \ - std::make_shared>( \ - F(), lhs.StealOp(), GetNodePtr(rhs))); \ -} \ - \ -template \ -< \ - typename TLeftSignal, \ - typename D, \ - typename TRightVal, \ - typename TRightOp, \ - typename TLeftVal = typename TLeftSignal::ValueT, \ - class = typename std::enable_if< \ - IsSignal::value>::type, \ - typename F = name ## OpFunctor, \ - typename S = typename std::result_of::type, \ - typename TOp = REACT_IMPL::FunctionOp, \ - TRightOp> \ -> \ -auto operator op(const TLeftSignal& lhs, TempSignal&& rhs) \ - -> TempSignal \ -{ \ - return TempSignal( \ - std::make_shared>( \ - F(), GetNodePtr(lhs), rhs.StealOp())); \ -} \ - \ -template \ -< \ - typename D, \ - typename TLeftVal, \ - typename TLeftOp, \ - typename TRightValIn, \ - typename TRightVal = typename std::decay::type, \ - class = typename std::enable_if< \ - ! IsSignal::value>::type, \ - typename F = name ## OpLFunctor, \ - typename S = typename std::result_of::type, \ - typename TOp = REACT_IMPL::FunctionOp \ -> \ -auto operator op(TempSignal&& lhs, TRightValIn&& rhs) \ - -> TempSignal \ -{ \ - return TempSignal( \ - std::make_shared>( \ - F( std::forward(rhs) ), lhs.StealOp())); \ -} \ - \ -template \ -< \ - typename TLeftValIn, \ - typename D, \ - typename TRightVal, \ - typename TRightOp, \ - typename TLeftVal = typename std::decay::type, \ - class = typename std::enable_if< \ - ! IsSignal::value>::type, \ - typename F = name ## OpRFunctor, \ - typename S = typename std::result_of::type, \ - typename TOp = REACT_IMPL::FunctionOp \ -> \ -auto operator op(TLeftValIn&& lhs, TempSignal&& rhs) \ - -> TempSignal \ -{ \ - return TempSignal( \ - std::make_shared>( \ - F( std::forward(lhs) ), rhs.StealOp())); \ -} - -REACT_DECLARE_OP(+, Addition) -REACT_DECLARE_OP(-, Subtraction) -REACT_DECLARE_OP(*, Multiplication) -REACT_DECLARE_OP(/, Division) -REACT_DECLARE_OP(%, Modulo) - -REACT_DECLARE_OP(==, Equal) -REACT_DECLARE_OP(!=, NotEqual) -REACT_DECLARE_OP(<, Less) -REACT_DECLARE_OP(<=, LessEqual) -REACT_DECLARE_OP(>, Greater) -REACT_DECLARE_OP(>=, GreaterEqual) - -REACT_DECLARE_OP(&&, LogicalAnd) -REACT_DECLARE_OP(||, LogicalOr) - -REACT_DECLARE_OP(&, BitwiseAnd) -REACT_DECLARE_OP(|, BitwiseOr) -REACT_DECLARE_OP(^, BitwiseXor) -//REACT_DECLARE_OP(<<, BitwiseLeftShift); // MSVC: Internal compiler error -//REACT_DECLARE_OP(>>, BitwiseRightShift); - -#undef REACT_DECLARE_OP - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Comma operator overload to create signal pack from 2 signals. -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename D, - typename TLeftVal, - typename TRightVal -> -auto operator,(const Signal& a, const Signal& b) - -> SignalPack -{ - return SignalPack(a, b); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Comma operator overload to append node to existing signal pack. -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename D, - typename ... TCurValues, - typename TAppendValue -> -auto operator,(const SignalPack& cur, const Signal& append) - -> SignalPack -{ - return SignalPack(cur, append); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// operator->* overload to connect signals to a function and return the resulting signal. -/////////////////////////////////////////////////////////////////////////////////////////////////// -// Single arg -template -< - typename D, - typename F, - template class TSignal, - typename TValue, - class = typename std::enable_if< - IsSignal>::value>::type -> -auto operator->*(const TSignal& arg, F&& func) - -> Signal::type> -{ - return REACT::MakeSignal(arg, std::forward(func)); -} - -// Multiple args -template -< - typename D, - typename F, - typename ... TValues -> -auto operator->*(const SignalPack& argPack, F&& func) - -> Signal::type> -{ - return REACT::MakeSignal(argPack, std::forward(func)); -} - /////////////////////////////////////////////////////////////////////////////////////////////////// /// Flatten /////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename D, - typename TInnerValue -> +template auto Flatten(const Signal>& outer) -> Signal { @@ -604,11 +167,7 @@ auto Flatten(const Signal>& outer) /////////////////////////////////////////////////////////////////////////////////////////////////// /// Signal /////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename D, - typename S -> +template class Signal : public REACT_IMPL::SignalBase { private: @@ -670,78 +229,14 @@ class Signal : public REACT_IMPL::SignalBase } }; -// Specialize for references -template -< - typename D, - typename S -> -class Signal : public REACT_IMPL::SignalBase> -{ -private: - using NodeT = REACT_IMPL::SignalNode>; - using NodePtrT = std::shared_ptr; - -public: - using ValueT = S; - - // Default ctor - Signal() = default; - - // Copy ctor - Signal(const Signal&) = default; - - // Move ctor - Signal(Signal&& other) : - Signal::SignalBase( std::move(other) ) - {} - - // Node ctor - explicit Signal(NodePtrT&& nodePtr) : - Signal::SignalBase( std::move(nodePtr) ) - {} - - // Copy assignment - Signal& operator=(const Signal&) = default; - - // Move assignment - Signal& operator=(Signal&& other) - { - Signal::SignalBase::operator=( std::move(other) ); - return *this; - } - - const S& Value() const { return Signal::SignalBase::getValue(); } - const S& operator()() const { return Signal::SignalBase::getValue(); } - - bool Equals(const Signal& other) const - { - return Signal::SignalBase::Equals(other); - } - - bool IsValid() const - { - return Signal::SignalBase::IsValid(); - } - - void SetWeightHint(WeightHint weight) - { - Signal::SignalBase::SetWeightHint(weight); - } -}; - /////////////////////////////////////////////////////////////////////////////////////////////////// /// VarSignal /////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename D, - typename S -> -class VarSignal : public Signal +template +class VarSignal : public Signal { private: - using NodeT = REACT_IMPL::VarNode; + using NodeT = REACT_IMPL::VarNode; using NodePtrT = std::shared_ptr; public: @@ -800,113 +295,12 @@ class VarSignal : public Signal } }; -// Specialize for references -template -< - typename D, - typename S -> -class VarSignal : public Signal> -{ -private: - using NodeT = REACT_IMPL::VarNode>; - using NodePtrT = std::shared_ptr; - -public: - using ValueT = S; - - // Default ctor - VarSignal() = default; - - // Copy ctor - VarSignal(const VarSignal&) = default; - - // Move ctor - VarSignal(VarSignal&& other) : - VarSignal::Signal( std::move(other) ) - {} - - // Node ctor - explicit VarSignal(NodePtrT&& nodePtr) : - VarSignal::Signal( std::move(nodePtr) ) - {} - - // Copy assignment - VarSignal& operator=(const VarSignal&) = default; - - // Move assignment - VarSignal& operator=(VarSignal&& other) - { - VarSignal::Signal::operator=( std::move(other) ); - return *this; - } - - void Set(std::reference_wrapper newValue) const - { - VarSignal::SignalBase::setValue(newValue); - } - - const VarSignal& operator<<=(std::reference_wrapper newValue) const - { - VarSignal::SignalBase::setValue(newValue); - return *this; - } -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// TempSignal -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename D, - typename S, - typename TOp -> -class TempSignal : public Signal -{ -private: - using NodeT = REACT_IMPL::SignalOpNode; - using NodePtrT = std::shared_ptr; - -public: - // Default ctor - TempSignal() = default; - - // Copy ctor - TempSignal(const TempSignal&) = default; - - // Move ctor - TempSignal(TempSignal&& other) : - TempSignal::Signal( std::move(other) ) - {} - - // Node ctor - explicit TempSignal(NodePtrT&& ptr) : - TempSignal::Signal( std::move(ptr) ) - {} - - // Copy assignment - TempSignal& operator=(const TempSignal&) = default; - - // Move assignemnt - TempSignal& operator=(TempSignal&& other) - { - TempSignal::Signal::operator=( std::move(other) ); - return *this; - } - - TOp StealOp() - { - return std::move(reinterpret_cast(this->ptr_.get())->StealOp()); - } -}; - /******************************************/ REACT_END /******************************************/ /***************************************/ REACT_IMPL_BEGIN /**************************************/ -template -bool Equals(const Signal& lhs, const Signal& rhs) +template +bool Equals(const Signal& lhs, const Signal& rhs) { return lhs.Equals(rhs); } diff --git a/include/react/TypeTraits.h b/include/react/TypeTraits.h index c6b6b7dd..bd0ac99c 100644 --- a/include/react/TypeTraits.h +++ b/include/react/TypeTraits.h @@ -16,47 +16,35 @@ /////////////////////////////////////////////////////////////////////////////////////////////////// /// Forward declarations /////////////////////////////////////////////////////////////////////////////////////////////////// -template +template class Signal; -template +template class VarSignal; -template -class TempSignal; - -template +template class Events; -template +template class EventSource; -template -class TempEvents; - template class Observer; -template -class ScopedObserver; - -template -class Continuation; - /////////////////////////////////////////////////////////////////////////////////////////////////// /// IsSignal /////////////////////////////////////////////////////////////////////////////////////////////////// template struct IsSignal { static const bool value = false; }; -template -struct IsSignal> { static const bool value = true; }; +template +struct IsSignal> { static const bool value = true; }; -template -struct IsSignal> { static const bool value = true; }; +template +struct IsSignal> { static const bool value = true; }; -template -struct IsSignal> { static const bool value = true; }; +template +constexpr bool IsSignalType = IsSignal::value; /////////////////////////////////////////////////////////////////////////////////////////////////// /// IsEvent @@ -64,14 +52,11 @@ struct IsSignal> { static const bool value = true; }; template struct IsEvent { static const bool value = false; }; -template -struct IsEvent> { static const bool value = true; }; - -template -struct IsEvent> { static const bool value = true; }; +template +struct IsEvent> { static const bool value = true; }; -template -struct IsEvent> { static const bool value = true; }; +template +struct IsEvent> { static const bool value = true; }; /////////////////////////////////////////////////////////////////////////////////////////////////// /// IsObserver @@ -82,41 +67,23 @@ struct IsObserver { static const bool value = false; }; template struct IsObserver> { static const bool value = true; }; -template -struct IsObserver> { static const bool value = true; }; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// IsContinuation -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -struct IsContinuation { static const bool value = false; }; - -template -struct IsContinuation> { static const bool value = true; }; - /////////////////////////////////////////////////////////////////////////////////////////////////// /// IsObservable /////////////////////////////////////////////////////////////////////////////////////////////////// template struct IsObservable { static const bool value = false; }; -template -struct IsObservable> { static const bool value = true; }; - -template -struct IsObservable> { static const bool value = true; }; - -template -struct IsObservable> { static const bool value = true; }; +template +struct IsObservable> { static const bool value = true; }; -template -struct IsObservable> { static const bool value = true; }; +template +struct IsObservable> { static const bool value = true; }; -template -struct IsObservable> { static const bool value = true; }; +template +struct IsObservable> { static const bool value = true; }; -template -struct IsObservable> { static const bool value = true; }; +template +struct IsObservable> { static const bool value = true; }; /////////////////////////////////////////////////////////////////////////////////////////////////// /// IsReactive @@ -124,44 +91,32 @@ struct IsObservable> { static const bool value = true; }; template struct IsReactive { static const bool value = false; }; -template -struct IsReactive> { static const bool value = true; }; - -template -struct IsReactive> { static const bool value = true; }; - -template -struct IsReactive> { static const bool value = true; }; +template +struct IsReactive> { static const bool value = true; }; -template -struct IsReactive> { static const bool value = true; }; +template +struct IsReactive> { static const bool value = true; }; -template -struct IsReactive> { static const bool value = true; }; +template +struct IsReactive> { static const bool value = true; }; -template -struct IsReactive> { static const bool value = true; }; +template +struct IsReactive> { static const bool value = true; }; template struct IsReactive> { static const bool value = true; }; -template -struct IsReactive> { static const bool value = true; }; - -template -struct IsReactive> { static const bool value = true; }; - /////////////////////////////////////////////////////////////////////////////////////////////////// /// DecayInput /////////////////////////////////////////////////////////////////////////////////////////////////// template struct DecayInput { using Type = T; }; -template -struct DecayInput> { using Type = Signal; }; +template +struct DecayInput> { using Type = Signal; }; -template -struct DecayInput> { using Type = Events; }; +template +struct DecayInput> { using Type = Events; }; /******************************************/ REACT_END /******************************************/ diff --git a/include/react/detail/graph/SignalNodes.h b/include/react/detail/graph/SignalNodes.h index eb438a0c..64cccaee 100644 --- a/include/react/detail/graph/SignalNodes.h +++ b/include/react/detail/graph/SignalNodes.h @@ -21,18 +21,14 @@ /////////////////////////////////////////////////////////////////////////////////////////////////// /// Forward declarations /////////////////////////////////////////////////////////////////////////////////////////////////// -template +template bool Equals(const L& lhs, const R& rhs); /////////////////////////////////////////////////////////////////////////////////////////////////// /// SignalNode /////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename D, - typename S -> -class SignalNode : public ObservableNode +template +class SignalNode : public ObservableNode { public: SignalNode() = default; @@ -52,19 +48,15 @@ class SignalNode : public ObservableNode S value_; }; -template -using SignalNodePtrT = std::shared_ptr>; +template +using SignalNodePtrT = std::shared_ptr>; /////////////////////////////////////////////////////////////////////////////////////////////////// /// VarNode /////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename D, - typename S -> +template class VarNode : - public SignalNode, + public SignalNode, public IInputNode { using Engine = typename VarNode::Engine; @@ -228,12 +220,10 @@ class FunctionOp : public ReactiveOpBase /////////////////////////////////////////////////////////////////////////////////////////////////// template < - typename D, typename S, typename TOp > -class SignalOpNode : - public SignalNode +class SignalOpNode : public SignalNode { using Engine = typename SignalOpNode::Engine; @@ -261,8 +251,7 @@ class SignalOpNode : using TurnT = typename D::Engine::TurnT; TurnT& turn = *reinterpret_cast(turnPtr); - REACT_LOG(D::Log().template Append( - GetObjectId(*this), turn.Id())); + REACT_LOG(D::Log().template Append(GetObjectId(*this), turn.Id())); bool changed = false; @@ -279,8 +268,7 @@ class SignalOpNode : } }// ~timer - REACT_LOG(D::Log().template Append( - GetObjectId(*this), turn.Id())); + REACT_LOG(D::Log().template Append(GetObjectId(*this), turn.Id())); if (changed) Engine::OnNodePulse(*this, turn); @@ -309,11 +297,10 @@ class SignalOpNode : /////////////////////////////////////////////////////////////////////////////////////////////////// template < - typename D, typename TOuter, typename TInner > -class FlattenNode : public SignalNode +class FlattenNode : public SignalNode { using Engine = typename FlattenNode::Engine; @@ -377,8 +364,8 @@ class FlattenNode : public SignalNode virtual int DependencyCount() const override { return 2; } private: - std::shared_ptr> outer_; - std::shared_ptr> inner_; + std::shared_ptr> outer_; + std::shared_ptr> inner_; }; /****************************************/ REACT_IMPL_END /***************************************/ From f9ca5bbb1915619da1ba2594cf60ce2fc1ccdcf5 Mon Sep 17 00:00:00 2001 From: schlangster Date: Mon, 25 Jul 2016 18:19:34 +0200 Subject: [PATCH 28/75] Refactor WIP. --- benchmarks/src/BenchmarkBase.h | 2 +- benchmarks/src/BenchmarkFanout.h | 2 +- benchmarks/src/BenchmarkGrid.h | 2 +- benchmarks/src/BenchmarkLifeSim.h | 2 +- benchmarks/src/BenchmarkRandom.h | 2 +- benchmarks/src/BenchmarkSequence.h | 2 +- benchmarks/src/Main.cpp | 2 +- examples/src/BasicAlgorithms.cpp | 2 +- examples/src/BasicComposition.cpp | 2 +- examples/src/BasicEvents.cpp | 2 +- examples/src/BasicObservers.cpp | 2 +- examples/src/BasicReactors.cpp | 2 +- examples/src/BasicSignals.cpp | 2 +- examples/src/BasicSynchronization.cpp | 2 +- include/react/Algorithm.h | 2 +- include/react/Domain.h | 246 +----------------- include/react/Event.h | 99 +++---- include/react/Observer.h | 2 +- include/react/Reactor.h | 2 +- include/react/Signal.h | 169 +++--------- include/react/TypeTraits.h | 45 +--- include/react/common/Concurrency.h | 2 +- include/react/common/Containers.h | 2 +- include/react/common/RefCounting.h | 2 +- include/react/common/SourceIdSet.h | 2 +- include/react/common/Timing.h | 2 +- include/react/common/TopoQueue.h | 2 +- include/react/common/Types.h | 2 +- include/react/common/Util.h | 2 +- include/react/detail/Defs.h | 2 +- include/react/detail/DomainBase.h | 2 +- include/react/detail/EngineBase.h | 2 +- include/react/detail/EventBase.h | 10 +- include/react/detail/IReactiveEngine.h | 133 ++-------- include/react/detail/IReactiveNode.h | 20 +- include/react/detail/ObserverBase.h | 2 +- include/react/detail/ReactiveBase.h | 2 +- include/react/detail/ReactiveInput.h | 2 +- include/react/detail/SignalBase.h | 2 +- include/react/detail/graph/AlgorithmNodes.h | 18 +- .../react/detail/graph/ContinuationNodes.h | 8 +- include/react/detail/graph/EventNodes.h | 131 +++++++--- include/react/detail/graph/GraphBase.h | 2 +- include/react/detail/graph/ObserverNodes.h | 8 +- include/react/detail/graph/ReactorNodes.h | 4 +- include/react/detail/graph/SignalNodes.h | 8 +- include/react/engine/PulsecountEngine.h | 2 +- include/react/engine/SubtreeEngine.h | 2 +- include/react/engine/ToposortEngine.h | 2 +- include/react/logging/EventLog.h | 2 +- include/react/logging/EventRecords.h | 2 +- include/react/logging/Logging.h | 2 +- src/engine/PulsecountEngine.cpp | 2 +- src/engine/SubtreeEngine.cpp | 2 +- src/engine/ToposortEngine.cpp | 2 +- src/logging/EventLog.cpp | 2 +- src/logging/EventRecords.cpp | 2 +- tests/src/EventStreamTest.cpp | 2 +- tests/src/EventStreamTest.h | 2 +- tests/src/EventStreamTestQ.cpp | 2 +- tests/src/MoveTest.cpp | 2 +- tests/src/MoveTest.h | 2 +- tests/src/ObserverTest.cpp | 2 +- tests/src/ObserverTest.h | 2 +- tests/src/ObserverTestQ.cpp | 2 +- tests/src/OperationsTest.cpp | 2 +- tests/src/OperationsTest.h | 2 +- tests/src/OperationsTestQ.cpp | 2 +- tests/src/ParallelizationTest.cpp | 2 +- tests/src/ParallelizationTest.h | 2 +- tests/src/SignalTest.cpp | 2 +- tests/src/SignalTest.h | 2 +- tests/src/SignalTestQ.cpp | 2 +- tests/src/TestUtil.h | 2 +- tests/src/TransactionTest.cpp | 2 +- tests/src/TransactionTest.h | 2 +- 76 files changed, 295 insertions(+), 730 deletions(-) diff --git a/benchmarks/src/BenchmarkBase.h b/benchmarks/src/BenchmarkBase.h index deaaf931..4b65306a 100644 --- a/benchmarks/src/BenchmarkBase.h +++ b/benchmarks/src/BenchmarkBase.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) diff --git a/benchmarks/src/BenchmarkFanout.h b/benchmarks/src/BenchmarkFanout.h index bc2c8b3e..6feaf567 100644 --- a/benchmarks/src/BenchmarkFanout.h +++ b/benchmarks/src/BenchmarkFanout.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) diff --git a/benchmarks/src/BenchmarkGrid.h b/benchmarks/src/BenchmarkGrid.h index 551f3db8..d719afaa 100644 --- a/benchmarks/src/BenchmarkGrid.h +++ b/benchmarks/src/BenchmarkGrid.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) diff --git a/benchmarks/src/BenchmarkLifeSim.h b/benchmarks/src/BenchmarkLifeSim.h index 1ebab386..39acc2df 100644 --- a/benchmarks/src/BenchmarkLifeSim.h +++ b/benchmarks/src/BenchmarkLifeSim.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) diff --git a/benchmarks/src/BenchmarkRandom.h b/benchmarks/src/BenchmarkRandom.h index 63cbd996..bf3ba9d1 100644 --- a/benchmarks/src/BenchmarkRandom.h +++ b/benchmarks/src/BenchmarkRandom.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) diff --git a/benchmarks/src/BenchmarkSequence.h b/benchmarks/src/BenchmarkSequence.h index f30d3064..5e96d3c7 100644 --- a/benchmarks/src/BenchmarkSequence.h +++ b/benchmarks/src/BenchmarkSequence.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) diff --git a/benchmarks/src/Main.cpp b/benchmarks/src/Main.cpp index 00284776..93a79d78 100644 --- a/benchmarks/src/Main.cpp +++ b/benchmarks/src/Main.cpp @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) diff --git a/examples/src/BasicAlgorithms.cpp b/examples/src/BasicAlgorithms.cpp index 69229ee5..dd20b7bc 100644 --- a/examples/src/BasicAlgorithms.cpp +++ b/examples/src/BasicAlgorithms.cpp @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) diff --git a/examples/src/BasicComposition.cpp b/examples/src/BasicComposition.cpp index da6075f5..d5354bae 100644 --- a/examples/src/BasicComposition.cpp +++ b/examples/src/BasicComposition.cpp @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) diff --git a/examples/src/BasicEvents.cpp b/examples/src/BasicEvents.cpp index 656a141b..0db396c3 100644 --- a/examples/src/BasicEvents.cpp +++ b/examples/src/BasicEvents.cpp @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) diff --git a/examples/src/BasicObservers.cpp b/examples/src/BasicObservers.cpp index ba5b3420..2c1b911e 100644 --- a/examples/src/BasicObservers.cpp +++ b/examples/src/BasicObservers.cpp @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) diff --git a/examples/src/BasicReactors.cpp b/examples/src/BasicReactors.cpp index 1e30cc1c..534c1346 100644 --- a/examples/src/BasicReactors.cpp +++ b/examples/src/BasicReactors.cpp @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) diff --git a/examples/src/BasicSignals.cpp b/examples/src/BasicSignals.cpp index 03707949..a5a82445 100644 --- a/examples/src/BasicSignals.cpp +++ b/examples/src/BasicSignals.cpp @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) diff --git a/examples/src/BasicSynchronization.cpp b/examples/src/BasicSynchronization.cpp index ec2be1c9..4a7f6529 100644 --- a/examples/src/BasicSynchronization.cpp +++ b/examples/src/BasicSynchronization.cpp @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) diff --git a/include/react/Algorithm.h b/include/react/Algorithm.h index 7caed812..edfca68e 100644 --- a/include/react/Algorithm.h +++ b/include/react/Algorithm.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) diff --git a/include/react/Domain.h b/include/react/Domain.h index e27c2514..b1fae362 100644 --- a/include/react/Domain.h +++ b/include/react/Domain.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) @@ -29,38 +29,22 @@ /////////////////////////////////////////////////////////////////////////////////////////////////// /// Forward declarations /////////////////////////////////////////////////////////////////////////////////////////////////// -template +template class Signal; -template +template class VarSignal; -template -class TempSignal; - -template +template class Events; -template +template class EventSource; -template -class TempEvents; - enum class Token; -template class Observer; -template -class ScopedObserver; - -template -class Reactor; - -template -class SignalPack; - /////////////////////////////////////////////////////////////////////////////////////////////////// /// Common types & constants /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -102,14 +86,14 @@ class TransactionStatus {} // Move ctor - inline TransactionStatus(TransactionStatus&& other) : + TransactionStatus(TransactionStatus&& other) : statePtr_( std::move(other.statePtr_) ) { other.statePtr_ = StateT::Create(); } // Move assignment - inline TransactionStatus& operator=(TransactionStatus&& other) + TransactionStatus& operator=(TransactionStatus&& other) { if (this != &other) { @@ -139,222 +123,6 @@ class TransactionStatus friend void AsyncTransaction(TransactionFlagsT flags, TransactionStatus& status, F&& func); }; -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Continuation -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename D, - typename D2 = D -> -class Continuation : public REACT_IMPL::ContinuationBase -{ -private: - using NodePtrT = REACT_IMPL::NodeBasePtrT; - -public: - using SourceDomainT = D; - using TargetDomainT = D2; - - // Default ctor - Continuation() = default; - - // Move ctor - Continuation(Continuation&& other) : - Continuation::ContinuationBase( std::move(other) ) - {} - - // Node ctor - explicit Continuation(NodePtrT&& nodePtr) : - Continuation::ContinuationBase( std::move(nodePtr) ) - {} - - // Move assignment - Continuation& operator=(Continuation&& other) - { - Continuation::ContinuationBase::operator=( std::move(other) ); - return *this; - } - - // Deleted copy ctor & assignment - Continuation(const Continuation&) = delete; - Continuation& operator=(const Continuation&) = delete; -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// MakeContinuation - Signals -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename D, - typename DOut = D, - typename S, - typename FIn -> -auto MakeContinuation(TransactionFlagsT flags, const Signal& trigger, FIn&& func) - -> Continuation -{ - static_assert(DOut::is_concurrent, - "MakeContinuation: Target domain does not support concurrent input."); - - using REACT_IMPL::SignalContinuationNode; - using F = typename std::decay::type; - - return Continuation( - std::make_shared>( - flags, GetNodePtr(trigger), std::forward(func))); -} - -template -< - typename D, - typename DOut = D, - typename S, - typename FIn -> -auto MakeContinuation(const Signal& trigger, FIn&& func) - -> Continuation -{ - return MakeContinuation(0, trigger, std::forward(func)); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// MakeContinuation - Events -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename D, - typename DOut = D, - typename E, - typename FIn -> -auto MakeContinuation(TransactionFlagsT flags, const Events& trigger, FIn&& func) - -> Continuation -{ - static_assert(DOut::is_concurrent, - "MakeContinuation: Target domain does not support concurrent input."); - - using REACT_IMPL::EventContinuationNode; - using REACT_IMPL::AddContinuationRangeWrapper; - using REACT_IMPL::IsCallableWith; - using REACT_IMPL::EventRange; - - using F = typename std::decay::type; - - using WrapperT = - typename std::conditional< - IsCallableWith>::value, - F, - typename std::conditional< - IsCallableWith::value, - AddContinuationRangeWrapper, - void - >::type - >::type; - - static_assert(! std::is_same::value, - "MakeContinuation: Passed function does not match any of the supported signatures."); - - return Continuation( - std::make_shared>( - flags, GetNodePtr(trigger), std::forward(func))); -} - -template -< - typename D, - typename DOut = D, - typename E, - typename FIn -> -auto MakeContinuation(const Events& trigger, FIn&& func) - -> Continuation -{ - return MakeContinuation(0, trigger, std::forward(func)); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// MakeContinuation - Synced -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename D, - typename DOut = D, - typename E, - typename FIn, - typename ... TDepValues -> -auto MakeContinuation(TransactionFlagsT flags, const Events& trigger, - const SignalPack& depPack, FIn&& func) - -> Continuation -{ - static_assert(DOut::is_concurrent, - "MakeContinuation: Target domain does not support concurrent input."); - - using REACT_IMPL::SyncedContinuationNode; - using REACT_IMPL::AddContinuationRangeWrapper; - using REACT_IMPL::IsCallableWith; - using REACT_IMPL::EventRange; - - using F = typename std::decay::type; - - using WrapperT = - typename std::conditional< - IsCallableWith, TDepValues ...>::value, - F, - typename std::conditional< - IsCallableWith::value, - AddContinuationRangeWrapper, - void - >::type - >::type; - - static_assert(! std::is_same::value, - "MakeContinuation: Passed function does not match any of the supported signatures."); - - struct NodeBuilder_ - { - NodeBuilder_(TransactionFlagsT flags, const Events& trigger, FIn&& func) : - MyFlags( flags ), - MyTrigger( trigger ), - MyFunc( std::forward(func) ) - {} - - auto operator()(const Signal& ... deps) - -> Continuation - { - return Continuation( - std::make_shared>( - MyFlags, - GetNodePtr(MyTrigger), - std::forward(MyFunc), GetNodePtr(deps) ...)); - } - - TransactionFlagsT MyFlags; - const Events& MyTrigger; - FIn MyFunc; - }; - - return REACT_IMPL::apply( - NodeBuilder_( flags, trigger, std::forward(func) ), - depPack.Data); -} - -template -< - typename D, - typename DOut = D, - typename E, - typename FIn, - typename ... TDepValues -> -auto MakeContinuation(const Events& trigger, - const SignalPack& depPack, FIn&& func) - -> Continuation -{ - return MakeContinuation(0, trigger, depPack, std::forward(func)); -} - /////////////////////////////////////////////////////////////////////////////////////////////// /// DoTransaction /////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/include/react/Event.h b/include/react/Event.h index 8ca754c2..599c2ad6 100644 --- a/include/react/Event.h +++ b/include/react/Event.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) @@ -25,30 +25,19 @@ /////////////////////////////////////////////////////////////////////////////////////////////////// /// Forward declarations /////////////////////////////////////////////////////////////////////////////////////////////////// -template -class Events; +template +class EventStream; -template +template class EventSource; enum class Token; -template +template class Signal; using REACT_IMPL::WeightHint; -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// MakeEventSource -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -auto MakeEventSource() -> EventSource -{ - using REACT_IMPL::EventSourceNode; - - return EventSource(std::make_shared>()); -} - /////////////////////////////////////////////////////////////////////////////////////////////////// /// Merge /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -284,24 +273,24 @@ struct Tokenizer Token operator()(const T&) const { return Token::value; } }; -template -auto Tokenize(TEvents&& source) -> decltype(Transform(source, Tokenizer{})) +template +auto Tokenize(T&& source) -> decltype(auto) { - return Transform(source, Tokenizer{}); + return Transform(source, Tokenizer{ }); } /////////////////////////////////////////////////////////////////////////////////////////////////// /// Events /////////////////////////////////////////////////////////////////////////////////////////////////// -template -class Events : public REACT_IMPL::EventStreamBase +template +class Events : public REACT_IMPL::EventStreamBase { private: - using NodeT = REACT_IMPL::EventStreamNode; - using NodePtrT = std::shared_ptr; + using NodeType = REACT_IMPL::EventStreamNode; + using NodePtrType = std::shared_ptr; public: - using ValueT = E; + using ValueType = T; // Default ctor Events() = default; @@ -310,24 +299,16 @@ class Events : public REACT_IMPL::EventStreamBase Events(const Events&) = default; // Move ctor - Events(Events&& other) : - Events::EventStreamBase( std::move(other) ) - {} + Events(Events&& other) = default; // Node ctor - explicit Events(NodePtrT&& nodePtr) : - Events::EventStreamBase( std::move(nodePtr) ) - {} + explicit Events(NodePtrT&& nodePtr) = default; // Copy assignment Events& operator=(const Events&) = default; // Move assignment - Events& operator=(Events&& other) - { - Events::EventStreamBase::operator=( std::move(other) ); - return *this; - } + Events& operator=(Events&& other) = default; bool Equals(const Events& other) const { @@ -344,43 +325,47 @@ class Events : public REACT_IMPL::EventStreamBase Events::EventStreamBase::SetWeightHint(weight); } - auto Tokenize() const - -> decltype(REACT::Tokenize(std::declval())) + auto Tokenize() const -> decltype(auto) { return REACT::Tokenize(*this); } template - auto Merge(TArgs&& ... args) const - -> decltype(REACT::Merge(std::declval(), std::forward(args) ...)) + auto Merge(TArgs&& ... args) const -> decltype(auto) { return REACT::Merge(*this, std::forward(args) ...); } template - auto Filter(F&& f) const - -> decltype(REACT::Filter(std::declval(), std::forward(f))) + auto Filter(F&& f) const -> decltype(auto) { return REACT::Filter(*this, std::forward(f)); } template - auto Transform(F&& f) const - -> decltype(REACT::Transform(std::declval(), std::forward(f))) + auto Transform(F&& f) const -> decltype(auto) { return REACT::Transform(*this, std::forward(f)); } + + template + static auto Create() -> EventSource + { + using REACT_IMPL::EventSourceNode; + + return EventSource(std::make_shared>()); + } }; /////////////////////////////////////////////////////////////////////////////////////////////////// /// EventSource /////////////////////////////////////////////////////////////////////////////////////////////////// -template -class EventSource : public Events +template +class EventSource : public Events { private: - using NodeT = REACT_IMPL::EventSourceNode; - using NodePtrT = std::shared_ptr; + using NodeType = REACT_IMPL::EventSourceNode; + using NodePtrType = std::shared_ptr; public: // Default ctor @@ -390,9 +375,7 @@ class EventSource : public Events EventSource(const EventSource&) = default; // Move ctor - EventSource(EventSource&& other) : - EventSource::Events( std::move(other) ) - {} + EventSource(EventSource&& other) = default; // Node ctor explicit EventSource(NodePtrT&& nodePtr) : @@ -403,15 +386,11 @@ class EventSource : public Events EventSource& operator=(const EventSource&) = default; // Move assignment - EventSource& operator=(EventSource&& other) - { - EventSource::Events::operator=( std::move(other) ); - return *this; - } + EventSource& operator=(EventSource&& other) = default; // Explicit emit - void Emit(const E& e) const { EventSource::EventStreamBase::emit(e); } - void Emit(E&& e) const { EventSource::EventStreamBase::emit(std::move(e)); } + void Emit(const T& e) const { EventSource::EventStreamBase::emit(e); } + void Emit(T&& e) const { EventSource::EventStreamBase::emit(std::move(e)); } void Emit() const { @@ -425,18 +404,18 @@ class EventSource : public Events void operator()() const { - static_assert(std::is_same::value, "Can't emit on non token stream."); + static_assert(std::is_same::value, "Can't emit on non token stream."); EventSource::EventStreamBase::emit(Token::value); } // Stream style - const EventSource& operator<<(const E& e) const + const EventSource& operator<<(const T& e) const { EventSource::EventStreamBase::emit(e); return *this; } - const EventSource& operator<<(E&& e) const + const EventSource& operator<<(T&& e) const { EventSource::EventStreamBase::emit(std::move(e)); return *this; diff --git a/include/react/Observer.h b/include/react/Observer.h index c9d986dc..17e72ebf 100644 --- a/include/react/Observer.h +++ b/include/react/Observer.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) diff --git a/include/react/Reactor.h b/include/react/Reactor.h index 2149dcac..92d3b006 100644 --- a/include/react/Reactor.h +++ b/include/react/Reactor.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) diff --git a/include/react/Signal.h b/include/react/Signal.h index ac5c6030..4bf28460 100644 --- a/include/react/Signal.h +++ b/include/react/Signal.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) @@ -29,129 +29,12 @@ /////////////////////////////////////////////////////////////////////////////////////////////////// /// Forward declarations /////////////////////////////////////////////////////////////////////////////////////////////////// -template +template class Signal; -template +template class VarSignal; -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// MakeVar -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename V, - typename S = typename std::decay::type, - class = typename std::enable_if::value>::type, - class = typename std::enable_if::value>::type -> -auto MakeVar(V&& value) -> VarSignal -{ - return VarSignal( - std::make_shared>( - std::forward(value))); -} - -template -auto MakeVar(std::reference_wrapper value) -> VarSignal -{ - return VarSignal( - std::make_shared>>(value)); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// MakeVar (higher order reactives) -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename V, - typename S = typename std::decay::type, - typename TInner = typename S::ValueT, - class = typename std::enable_if::value>::type -> -auto MakeVar(V&& value) - -> VarSignal> -{ - return VarSignal>( - std::make_shared>>( - std::forward(value))); -} - -template -< - - typename V, - typename S = typename std::decay::type, - typename TInner = typename S::ValueT, - class = typename std::enable_if< - IsEvent::value>::type -> -auto MakeVar(V&& value) - -> VarSignal> -{ - return VarSignal>( - std::make_shared>>( - std::forward(value))); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// MakeSignal -/////////////////////////////////////////////////////////////////////////////////////////////////// -// Single arg -template -< - - typename TValue, - typename FIn, - typename F = typename std::decay::type, - typename S = typename std::result_of::type, - typename TOp = REACT_IMPL::FunctionOp> -> -auto MakeSignal(const Signal& arg, FIn&& func) - -> TempSignal -{ - return TempSignal( - std::make_shared>( - std::forward(func), GetNodePtr(arg))); -} - -// Multiple args -template -< - - typename ... TValues, - typename FIn, - typename F = typename std::decay::type, - typename S = typename std::result_of::type, - typename TOp = REACT_IMPL::FunctionOp ...> -> -auto MakeSignal(const SignalPack& argPack, FIn&& func) - -> TempSignal -{ - using REACT_IMPL::SignalOpNode; - - struct NodeBuilder_ - { - NodeBuilder_(FIn&& func) : - MyFunc( std::forward(func) ) - {} - - auto operator()(const Signal& ... args) - -> TempSignal - { - return TempSignal( - std::make_shared>( - std::forward(MyFunc), GetNodePtr(args) ...)); - } - - FIn MyFunc; - }; - - return REACT_IMPL::apply( - NodeBuilder_( std::forward(func) ), - argPack.Data); -} - /////////////////////////////////////////////////////////////////////////////////////////////////// /// Flatten /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -167,15 +50,15 @@ auto Flatten(const Signal>& outer) /////////////////////////////////////////////////////////////////////////////////////////////////// /// Signal /////////////////////////////////////////////////////////////////////////////////////////////////// -template -class Signal : public REACT_IMPL::SignalBase +template +class Signal : public REACT_IMPL::SignalBase { private: - using NodeT = REACT_IMPL::SignalNode; - using NodePtrT = std::shared_ptr; + using NodeType = REACT_IMPL::SignalNode; + using NodePtrType = std::shared_ptr; public: - using ValueT = S; + using ValueType = T; // Default ctor Signal() = default; @@ -184,12 +67,10 @@ class Signal : public REACT_IMPL::SignalBase Signal(const Signal&) = default; // Move ctor - Signal(Signal&& other) : - Signal::SignalBase( std::move(other) ) - {} + Signal(Signal&& other) = default; // Node ctor - explicit Signal(NodePtrT&& nodePtr) : + explicit Signal(NodePtrType&& nodePtr) : Signal::SignalBase( std::move(nodePtr) ) {} @@ -197,13 +78,9 @@ class Signal : public REACT_IMPL::SignalBase Signal& operator=(const Signal&) = default; // Move assignment - Signal& operator=(Signal&& other) - { - Signal::SignalBase::operator=( std::move(other) ); - return *this; - } + Signal& operator=(Signal&& other) = default; - const S& Value() const { return Signal::SignalBase::getValue(); } + const S& Get() const { return Signal::SignalBase::getValue(); } const S& operator()() const { return Signal::SignalBase::getValue(); } bool Equals(const Signal& other) const @@ -227,6 +104,19 @@ class Signal : public REACT_IMPL::SignalBase "Flatten requires a Signal or Events value type."); return REACT::Flatten(*this); } + + template + < + typename ... Ts, + typename FIn, + typename F = typename std::decay::type + > + static auto Create(FIn&& func, const Signal& ... args) -> Signal + { + return Signal( + std::make_shared>( + std::forward(func), GetNodePtr(args) ...)); + } }; /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -293,6 +183,15 @@ class VarSignal : public Signal { VarSignal::SignalBase::modifyValue(func); } + + /// Create + template + static auto Create(V&& value) -> VarSignal + { + return VarSignal( + std::make_shared>( + std::forward(value))); + } }; /******************************************/ REACT_END /******************************************/ diff --git a/include/react/TypeTraits.h b/include/react/TypeTraits.h index bd0ac99c..97c12654 100644 --- a/include/react/TypeTraits.h +++ b/include/react/TypeTraits.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) @@ -16,19 +16,18 @@ /////////////////////////////////////////////////////////////////////////////////////////////////// /// Forward declarations /////////////////////////////////////////////////////////////////////////////////////////////////// -template +template class Signal; -template +template class VarSignal; -template +template class Events; -template +template class EventSource; -template class Observer; /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -43,9 +42,6 @@ struct IsSignal> { static const bool value = true; }; template struct IsSignal> { static const bool value = true; }; -template -constexpr bool IsSignalType = IsSignal::value; - /////////////////////////////////////////////////////////////////////////////////////////////////// /// IsEvent /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -58,33 +54,6 @@ struct IsEvent> { static const bool value = true; }; template struct IsEvent> { static const bool value = true; }; -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// IsObserver -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -struct IsObserver { static const bool value = false; }; - -template -struct IsObserver> { static const bool value = true; }; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// IsObservable -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -struct IsObservable { static const bool value = false; }; - -template -struct IsObservable> { static const bool value = true; }; - -template -struct IsObservable> { static const bool value = true; }; - -template -struct IsObservable> { static const bool value = true; }; - -template -struct IsObservable> { static const bool value = true; }; - /////////////////////////////////////////////////////////////////////////////////////////////////// /// IsReactive /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -103,8 +72,8 @@ struct IsReactive> { static const bool value = true; }; template struct IsReactive> { static const bool value = true; }; -template -struct IsReactive> { static const bool value = true; }; +template <> +struct IsReactive { static const bool value = true; }; /////////////////////////////////////////////////////////////////////////////////////////////////// /// DecayInput diff --git a/include/react/common/Concurrency.h b/include/react/common/Concurrency.h index e27fd9ba..0a5c350c 100644 --- a/include/react/common/Concurrency.h +++ b/include/react/common/Concurrency.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) diff --git a/include/react/common/Containers.h b/include/react/common/Containers.h index 9b77de06..1839bd46 100644 --- a/include/react/common/Containers.h +++ b/include/react/common/Containers.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) diff --git a/include/react/common/RefCounting.h b/include/react/common/RefCounting.h index 3a84dbb4..f2cd518a 100644 --- a/include/react/common/RefCounting.h +++ b/include/react/common/RefCounting.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) diff --git a/include/react/common/SourceIdSet.h b/include/react/common/SourceIdSet.h index 1cf89210..b1a3eeb0 100644 --- a/include/react/common/SourceIdSet.h +++ b/include/react/common/SourceIdSet.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) diff --git a/include/react/common/Timing.h b/include/react/common/Timing.h index 3775661d..84c58006 100644 --- a/include/react/common/Timing.h +++ b/include/react/common/Timing.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) diff --git a/include/react/common/TopoQueue.h b/include/react/common/TopoQueue.h index 8084d419..b86885ff 100644 --- a/include/react/common/TopoQueue.h +++ b/include/react/common/TopoQueue.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) diff --git a/include/react/common/Types.h b/include/react/common/Types.h index 5d747eee..0545f858 100644 --- a/include/react/common/Types.h +++ b/include/react/common/Types.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) diff --git a/include/react/common/Util.h b/include/react/common/Util.h index 39741ed7..19fe74f4 100644 --- a/include/react/common/Util.h +++ b/include/react/common/Util.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) diff --git a/include/react/detail/Defs.h b/include/react/detail/Defs.h index 477ad6b4..5dd2f91f 100644 --- a/include/react/detail/Defs.h +++ b/include/react/detail/Defs.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) diff --git a/include/react/detail/DomainBase.h b/include/react/detail/DomainBase.h index 67c7e8ae..7327874b 100644 --- a/include/react/detail/DomainBase.h +++ b/include/react/detail/DomainBase.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) diff --git a/include/react/detail/EngineBase.h b/include/react/detail/EngineBase.h index 7b9af9de..501c9c26 100644 --- a/include/react/detail/EngineBase.h +++ b/include/react/detail/EngineBase.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) diff --git a/include/react/detail/EventBase.h b/include/react/detail/EventBase.h index 583651aa..bf518860 100644 --- a/include/react/detail/EventBase.h +++ b/include/react/detail/EventBase.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) @@ -22,12 +22,8 @@ /////////////////////////////////////////////////////////////////////////////////////////////////// /// EventStreamBase /////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename D, - typename E -> -class EventStreamBase : public CopyableReactive> +template +class EventStreamBase : public ReactiveBase> { public: EventStreamBase() = default; diff --git a/include/react/detail/IReactiveEngine.h b/include/react/detail/IReactiveEngine.h index 9a422cb8..b4e0b83c 100644 --- a/include/react/detail/IReactiveEngine.h +++ b/include/react/detail/IReactiveEngine.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) @@ -21,132 +21,29 @@ /////////////////////////////////////////////////////////////////////////////////////////////////// /// IReactiveEngine /////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename TNode, - typename TTurn -> struct IReactiveEngine { - using NodeT = TNode; - using TurnT = TTurn; + using NodeId = uint; + using TurnId = uint; - void OnTurnAdmissionStart(TurnT& turn) {} - void OnTurnAdmissionEnd(TurnT& turn) {} + void OnTurnAdmissionStart(TurnId& turn) {} + void OnTurnAdmissionEnd(TurnId& turn) {} - void OnInputChange(NodeT& node, TurnT& turn) {} + void OnInputChange(NodeId& node, TurnId& turn) {} - void Propagate(TurnT& turn) {} + void Propagate(TurnId& turn) {} - void OnNodeCreate(NodeT& node) {} - void OnNodeDestroy(NodeT& node) {} + void OnNodeCreate(NodeId& node) {} + void OnNodeDestroy(NodeId& node) {} - void OnNodeAttach(NodeT& node, NodeT& parent) {} - void OnNodeDetach(NodeT& node, NodeT& parent) {} + void OnNodeAttach(NodeId node, NodeId parent) {} + void OnNodeDetach(NodeId node, NodeId parent) {} - void OnNodePulse(NodeT& node, TurnT& turn) {} - void OnNodeIdlePulse(NodeT& node, TurnT& turn) {} + void OnNodePulse(NodeId& node, TurnId& turn) {} + void OnNodeIdlePulse(NodeId& node, TurnId& turn) {} - void OnDynamicNodeAttach(NodeT& node, NodeT& parent, TurnT& turn) {} - void OnDynamicNodeDetach(NodeT& node, NodeT& parent, TurnT& turn) {} -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// EngineInterface - Static wrapper for IReactiveEngine -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename D, - typename TEngine -> -struct EngineInterface -{ - using NodeT = typename TEngine::NodeT; - using TurnT = typename TEngine::TurnT; - - static TEngine& Instance() - { - static TEngine engine; - return engine; - } - - static void OnTurnAdmissionStart(TurnT& turn) - { - Instance().OnTurnAdmissionStart(turn); - } - - static void OnTurnAdmissionEnd(TurnT& turn) - { - Instance().OnTurnAdmissionEnd(turn); - } - - static void OnInputChange(NodeT& node, TurnT& turn) - { - REACT_LOG(D::Log().template Append( - GetObjectId(node), turn.Id())); - Instance().OnInputChange(node, turn); - } - - static void Propagate(TurnT& turn) - { - Instance().Propagate(turn); - } - - static void OnNodeCreate(NodeT& node) - { - REACT_LOG(D::Log().template Append( - GetObjectId(node), node.GetNodeType())); - Instance().OnNodeCreate(node); - } - - static void OnNodeDestroy(NodeT& node) - { - REACT_LOG(D::Log().template Append( - GetObjectId(node))); - Instance().OnNodeDestroy(node); - } - - static void OnNodeAttach(NodeT& node, NodeT& parent) - { - REACT_LOG(D::Log().template Append( - GetObjectId(node), GetObjectId(parent))); - Instance().OnNodeAttach(node, parent); - } - - static void OnNodeDetach(NodeT& node, NodeT& parent) - { - REACT_LOG(D::Log().template Append( - GetObjectId(node), GetObjectId(parent))); - Instance().OnNodeDetach(node, parent); - } - - static void OnNodePulse(NodeT& node, TurnT& turn) - { - REACT_LOG(D::Log().template Append( - GetObjectId(node), turn.Id())); - Instance().OnNodePulse(node, turn); - } - - static void OnNodeIdlePulse(NodeT& node, TurnT& turn) - { - REACT_LOG(D::Log().template Append( - GetObjectId(node), turn.Id())); - Instance().OnNodeIdlePulse(node, turn); - } - - static void OnDynamicNodeAttach(NodeT& node, NodeT& parent, TurnT& turn) - { - REACT_LOG(D::Log().template Append( - GetObjectId(node), GetObjectId(parent), turn.Id())); - Instance().OnDynamicNodeAttach(node, parent, turn); - } - - static void OnDynamicNodeDetach(NodeT& node, NodeT& parent, TurnT& turn) - { - REACT_LOG(D::Log().template Append( - GetObjectId(node), GetObjectId(parent), turn.Id())); - Instance().OnDynamicNodeDetach(node, parent, turn); - } + void OnDynamicNodeAttach(NodeId& node, NodeId& parent, TurnId& turn) {} + void OnDynamicNodeDetach(NodeId& node, NodeId& parent, TurnId& turn) {} }; /////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/include/react/detail/IReactiveNode.h b/include/react/detail/IReactiveNode.h index b4d2e79c..34967834 100644 --- a/include/react/detail/IReactiveNode.h +++ b/include/react/detail/IReactiveNode.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) @@ -13,6 +13,12 @@ /***************************************/ REACT_IMPL_BEGIN /**************************************/ +enum class EUpdateResult +{ + UNCHANGED, + CHANGED +}; + /////////////////////////////////////////////////////////////////////////////////////////////////// /// IReactiveNode /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -25,24 +31,24 @@ struct IReactiveNode // Note: Could get rid of this ugly ptr by adding a template parameter to the interface // But that would mean all engine nodes need that template parameter too - so rather cast - virtual void Tick(void* turnPtr) = 0; + virtual EUpdateResult Update() = 0; /// Input nodes can be manipulated externally. - virtual bool IsInputNode() const = 0; + virtual bool IsInputNode() const = 0; /// Output nodes can't have any successors. - virtual bool IsOutputNode() const = 0; + virtual bool IsOutputNode() const = 0; /// Dynamic nodes may change in topology as a result of tick. - virtual bool IsDynamicNode() const = 0; + virtual bool IsDynamicNode() const = 0; // Number of predecessors. // This information is statically available at compile time on the graph layer, // so the engine does not have to calculate it again. - virtual int DependencyCount() const = 0; + virtual int DependencyCount() const = 0; // Heavyweight nodes are worth parallelizing. - virtual bool IsHeavyweight() const = 0; + virtual bool IsHeavyweight() const = 0; }; /////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/include/react/detail/ObserverBase.h b/include/react/detail/ObserverBase.h index 814e0207..73f637fd 100644 --- a/include/react/detail/ObserverBase.h +++ b/include/react/detail/ObserverBase.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) diff --git a/include/react/detail/ReactiveBase.h b/include/react/detail/ReactiveBase.h index d7f32124..12dafd82 100644 --- a/include/react/detail/ReactiveBase.h +++ b/include/react/detail/ReactiveBase.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) diff --git a/include/react/detail/ReactiveInput.h b/include/react/detail/ReactiveInput.h index 3589d8c7..ffcbcd6b 100644 --- a/include/react/detail/ReactiveInput.h +++ b/include/react/detail/ReactiveInput.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) diff --git a/include/react/detail/SignalBase.h b/include/react/detail/SignalBase.h index 6c41b9df..9b497136 100644 --- a/include/react/detail/SignalBase.h +++ b/include/react/detail/SignalBase.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) diff --git a/include/react/detail/graph/AlgorithmNodes.h b/include/react/detail/graph/AlgorithmNodes.h index 454fdfbb..eb158c4b 100644 --- a/include/react/detail/graph/AlgorithmNodes.h +++ b/include/react/detail/graph/AlgorithmNodes.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) @@ -110,7 +110,7 @@ class IterateNode : Engine::OnNodeDestroy(*this); } - virtual void Tick(void* turnPtr) override + virtual void Update(void* turnPtr) override { using TurnT = typename D::Engine::TurnT; TurnT& turn = *reinterpret_cast(turnPtr); @@ -183,7 +183,7 @@ class IterateByRefNode : Engine::OnNodeDestroy(*this); } - virtual void Tick(void* turnPtr) override + virtual void Update(void* turnPtr) override { using TurnT = typename D::Engine::TurnT; TurnT& turn = *reinterpret_cast(turnPtr); @@ -257,7 +257,7 @@ class SyncedIterateNode : Engine::OnNodeDestroy(*this); } - virtual void Tick(void* turnPtr) override + virtual void Update(void* turnPtr) override { using TurnT = typename D::Engine::TurnT; TurnT& turn = *reinterpret_cast(turnPtr); @@ -351,7 +351,7 @@ class SyncedIterateByRefNode : Engine::OnNodeDestroy(*this); } - virtual void Tick(void* turnPtr) override + virtual void Update(void* turnPtr) override { using TurnT = typename D::Engine::TurnT; TurnT& turn = *reinterpret_cast(turnPtr); @@ -429,7 +429,7 @@ class HoldNode : public SignalNode virtual const char* GetNodeType() const override { return "HoldNode"; } - virtual void Tick(void* turnPtr) override + virtual void Update(void* turnPtr) override { using TurnT = typename D::Engine::TurnT; TurnT& turn = *reinterpret_cast(turnPtr); @@ -497,7 +497,7 @@ class SnapshotNode : public SignalNode Engine::OnNodeDestroy(*this); } - virtual void Tick(void* turnPtr) override + virtual void Update(void* turnPtr) override { using TurnT = typename D::Engine::TurnT; TurnT& turn = *reinterpret_cast(turnPtr); @@ -564,7 +564,7 @@ class MonitorNode : public EventStreamNode Engine::OnNodeDestroy(*this); } - virtual void Tick(void* turnPtr) override + virtual void Update(void* turnPtr) override { using TurnT = typename D::Engine::TurnT; TurnT& turn = *reinterpret_cast(turnPtr); @@ -624,7 +624,7 @@ class PulseNode : public EventStreamNode Engine::OnNodeDestroy(*this); } - virtual void Tick(void* turnPtr) override + virtual void Update(void* turnPtr) override { typedef typename D::Engine::TurnT TurnT; TurnT& turn = *reinterpret_cast(turnPtr); diff --git a/include/react/detail/graph/ContinuationNodes.h b/include/react/detail/graph/ContinuationNodes.h index c841d23f..6d494453 100644 --- a/include/react/detail/graph/ContinuationNodes.h +++ b/include/react/detail/graph/ContinuationNodes.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) @@ -111,7 +111,7 @@ class SignalContinuationNode : public ContinuationNode virtual const char* GetNodeType() const override { return "SignalContinuationNode"; } virtual int DependencyCount() const override { return 1; } - virtual void Tick(void* turnPtr) override + virtual void Update(void* turnPtr) override { #ifdef REACT_ENABLE_LOGGING using TurnT = typename D::Engine::TurnT; @@ -183,7 +183,7 @@ class EventContinuationNode : public ContinuationNode virtual const char* GetNodeType() const override { return "EventContinuationNode"; } virtual int DependencyCount() const override { return 1; } - virtual void Tick(void* turnPtr) override + virtual void Update(void* turnPtr) override { #ifdef REACT_ENABLE_LOGGING using TurnT = typename D::Engine::TurnT; @@ -293,7 +293,7 @@ class SyncedContinuationNode : public ContinuationNode virtual const char* GetNodeType() const override { return "SyncedContinuationNode"; } virtual int DependencyCount() const override { return 1 + sizeof...(TDepValues); } - virtual void Tick(void* turnPtr) override + virtual void Update(void* turnPtr) override { using TurnT = typename D::Engine::TurnT; TurnT& turn = *reinterpret_cast(turnPtr); diff --git a/include/react/detail/graph/EventNodes.h b/include/react/detail/graph/EventNodes.h index 850b36c2..f6c750cc 100644 --- a/include/react/detail/graph/EventNodes.h +++ b/include/react/detail/graph/EventNodes.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) @@ -27,7 +27,7 @@ /////////////////////////////////////////////////////////////////////////////////////////////////// /// Forward declarations /////////////////////////////////////////////////////////////////////////////////////////////////// -template +template class SignalNode; /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -47,19 +47,11 @@ struct BufferClearAccessPolicy : /////////////////////////////////////////////////////////////////////////////////////////////////// /// EventStreamNode /////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename D, - typename E -> -class EventStreamNode : - public ObservableNode, - private BufferClearAccessPolicy +template +class EventStreamNode : public ObservableNode { public: - using DataT = std::vector; - using EngineT = typename D::Engine; - using TurnT = typename EngineT::TurnT; + using StorageType = std::vector; EventStreamNode() = default; @@ -75,10 +67,14 @@ class EventStreamNode : }); } - DataT& Events() { return events_; } + StorageType& Events() + { return events_; } + + const StorageType& Events() const + { return events_; } protected: - DataT events_; + StorageType events_; private: uint curTurnId_ { (std::numeric_limits::max)() }; @@ -90,17 +86,11 @@ using EventStreamNodePtrT = std::shared_ptr>; /////////////////////////////////////////////////////////////////////////////////////////////////// /// EventSourceNode /////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename D, - typename E -> +template class EventSourceNode : - public EventStreamNode, + public EventStreamNode, public IInputNode { - using Engine = typename EventSourceNode::Engine; - public: EventSourceNode() : EventSourceNode::EventStreamNode{ } @@ -117,7 +107,7 @@ class EventSourceNode : virtual bool IsInputNode() const override { return true; } virtual int DependencyCount() const override { return 0; } - virtual void Tick(void* turnPtr) override + virtual void Update(void* turnPtr) override { REACT_ASSERT(false, "Ticked EventSourceNode\n"); } @@ -157,25 +147,86 @@ class EventSourceNode : bool changedFlag_ = false; }; +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// EventOpNode +/////////////////////////////////////////////////////////////////////////////////////////////////// +template +< + typename T, + typename ... Ds +> +class EventMergeNode : public EventStreamNode +{ +public: + template + EventMergeNode(Us&& ... args) : + EventOpNode::EventStreamNode( ), + op_( std::forward(args) ... ) + { + Engine::OnNodeCreate(*this); + op_.template Attach(*this); + } + + ~EventOpNode() + { + if (!wasOpStolen_) + op_.template Detach(*this); + Engine::OnNodeDestroy(*this); + } + + virtual EUpdateResult Update() override + { + using TurnT = typename D::Engine::TurnT; + TurnT& turn = *reinterpret_cast(turnPtr); + + this->SetCurrentTurn(turn, true); + + {// timer + size_t count = 0; + using TimerT = typename EventOpNode::ScopedUpdateTimer; + TimerT scopedTimer( *this, count ); + + op_.Collect(turn, EventCollector( this->events_ )); + + // Note: Count was passed by reference, so we can still change before the dtor + // of the scoped timer is called + count = this->events_.size(); + }// ~timer + + if (! this->events_.empty()) + return EUpdateResult::CHANGED; + else + return EUpdateResult::UNCHANGED; + } + + virtual const char* GetNodeType() const override + { return "EventOpNode"; } + + virtual int DependencyCount() const override + { return TOp::dependency_count; } + +private: + TOp op_; + bool wasOpStolen_ = false; +}; + /////////////////////////////////////////////////////////////////////////////////////////////////// /// EventMergeOp /////////////////////////////////////////////////////////////////////////////////////////////////// template < - typename E, - typename ... TDeps + typename T, + typename ... Ds > -class EventMergeOp : public ReactiveOpBase +class EventMergeOp : public ReactiveOpBase { public: - template - EventMergeOp(TDepsIn&& ... deps) : - EventMergeOp::ReactiveOpBase(DontMove(), std::forward(deps) ...) + template + EventMergeOp(Us&& ... deps) : + EventMergeOp::ReactiveOpBase(DontMove(), std::forward(deps) ...) {} - EventMergeOp(EventMergeOp&& other) : - EventMergeOp::ReactiveOpBase( std::move(other) ) - {} + EventMergeOp(EventMergeOp&& other) = default; template void Collect(const TTurn& turn, const TCollector& collector) const @@ -406,7 +457,7 @@ class EventOpNode : Engine::OnNodeDestroy(*this); } - virtual void Tick(void* turnPtr) override + virtual void Update(void* turnPtr) override { using TurnT = typename D::Engine::TurnT; TurnT& turn = *reinterpret_cast(turnPtr); @@ -500,7 +551,7 @@ class EventFlattenNode : public EventStreamNode virtual bool IsDynamicNode() const override { return true; } virtual int DependencyCount() const override { return 2; } - virtual void Tick(void* turnPtr) override + virtual void Update(void* turnPtr) override { typedef typename D::Engine::TurnT TurnT; TurnT& turn = *reinterpret_cast(turnPtr); @@ -588,7 +639,7 @@ class SyncedEventTransformNode : Engine::OnNodeDestroy(*this); } - virtual void Tick(void* turnPtr) override + virtual void Update(void* turnPtr) override { using TurnT = typename D::Engine::TurnT; TurnT& turn = *reinterpret_cast(turnPtr); @@ -679,7 +730,7 @@ class SyncedEventFilterNode : Engine::OnNodeDestroy(*this); } - virtual void Tick(void* turnPtr) override + virtual void Update(void* turnPtr) override { using TurnT = typename D::Engine::TurnT; TurnT& turn = *reinterpret_cast(turnPtr); @@ -766,7 +817,7 @@ class EventProcessingNode : Engine::OnNodeDestroy(*this); } - virtual void Tick(void* turnPtr) override + virtual void Update(void* turnPtr) override { using TurnT = typename D::Engine::TurnT; TurnT& turn = *reinterpret_cast(turnPtr); @@ -846,7 +897,7 @@ class SyncedEventProcessingNode : Engine::OnNodeDestroy(*this); } - virtual void Tick(void* turnPtr) override + virtual void Update(void* turnPtr) override { using TurnT = typename D::Engine::TurnT; TurnT& turn = *reinterpret_cast(turnPtr); @@ -932,7 +983,7 @@ class EventJoinNode : Engine::OnNodeDestroy(*this); } - virtual void Tick(void* turnPtr) override + virtual void Update(void* turnPtr) override { TurnT& turn = *reinterpret_cast(turnPtr); diff --git a/include/react/detail/graph/GraphBase.h b/include/react/detail/graph/GraphBase.h index b7d79d27..66993500 100644 --- a/include/react/detail/graph/GraphBase.h +++ b/include/react/detail/graph/GraphBase.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) diff --git a/include/react/detail/graph/ObserverNodes.h b/include/react/detail/graph/ObserverNodes.h index 351a54e5..b597e828 100644 --- a/include/react/detail/graph/ObserverNodes.h +++ b/include/react/detail/graph/ObserverNodes.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) @@ -118,7 +118,7 @@ class SignalObserverNode : virtual const char* GetNodeType() const override { return "SignalObserverNode"; } virtual int DependencyCount() const override { return 1; } - virtual void Tick(void* turnPtr) override + virtual void Update(void* turnPtr) override { #ifdef REACT_ENABLE_LOGGING using TurnT = typename D::Engine::TurnT; @@ -200,7 +200,7 @@ class EventObserverNode : virtual const char* GetNodeType() const override { return "EventObserverNode"; } virtual int DependencyCount() const override { return 1; } - virtual void Tick(void* turnPtr) override + virtual void Update(void* turnPtr) override { #ifdef REACT_ENABLE_LOGGING using TurnT = typename D::Engine::TurnT; @@ -288,7 +288,7 @@ class SyncedObserverNode : virtual const char* GetNodeType() const override { return "SyncedObserverNode"; } virtual int DependencyCount() const override { return 1 + sizeof...(TDepValues); } - virtual void Tick(void* turnPtr) override + virtual void Update(void* turnPtr) override { using TurnT = typename D::Engine::TurnT; TurnT& turn = *reinterpret_cast(turnPtr); diff --git a/include/react/detail/graph/ReactorNodes.h b/include/react/detail/graph/ReactorNodes.h index b693a5f0..c85cdcc0 100644 --- a/include/react/detail/graph/ReactorNodes.h +++ b/include/react/detail/graph/ReactorNodes.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) @@ -88,7 +88,7 @@ class ReactorNode : virtual bool IsDynamicNode() const override { return true; } virtual bool IsOutputNode() const override { return true; } - virtual void Tick(void* turnPtr) override + virtual void Update(void* turnPtr) override { turnPtr_ = reinterpret_cast(turnPtr); diff --git a/include/react/detail/graph/SignalNodes.h b/include/react/detail/graph/SignalNodes.h index 64cccaee..9ea74832 100644 --- a/include/react/detail/graph/SignalNodes.h +++ b/include/react/detail/graph/SignalNodes.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) @@ -79,7 +79,7 @@ class VarNode : virtual bool IsInputNode() const override { return true; } virtual int DependencyCount() const override { return 0; } - virtual void Tick(void* turnPtr) override + virtual void Update(void* turnPtr) override { REACT_ASSERT(false, "Ticked VarNode\n"); } @@ -246,7 +246,7 @@ class SignalOpNode : public SignalNode Engine::OnNodeDestroy(*this); } - virtual void Tick(void* turnPtr) override + virtual void Update(void* turnPtr) override { using TurnT = typename D::Engine::TurnT; TurnT& turn = *reinterpret_cast(turnPtr); @@ -323,7 +323,7 @@ class FlattenNode : public SignalNode Engine::OnNodeDestroy(*this); } - virtual void Tick(void* turnPtr) override + virtual void Update(void* turnPtr) override { using TurnT = typename D::Engine::TurnT; TurnT& turn = *reinterpret_cast(turnPtr); diff --git a/include/react/engine/PulsecountEngine.h b/include/react/engine/PulsecountEngine.h index ed813e54..95308f3c 100644 --- a/include/react/engine/PulsecountEngine.h +++ b/include/react/engine/PulsecountEngine.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) diff --git a/include/react/engine/SubtreeEngine.h b/include/react/engine/SubtreeEngine.h index 9a84d7cb..cfda49d1 100644 --- a/include/react/engine/SubtreeEngine.h +++ b/include/react/engine/SubtreeEngine.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) diff --git a/include/react/engine/ToposortEngine.h b/include/react/engine/ToposortEngine.h index 9f8f693c..331ecd11 100644 --- a/include/react/engine/ToposortEngine.h +++ b/include/react/engine/ToposortEngine.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) diff --git a/include/react/logging/EventLog.h b/include/react/logging/EventLog.h index e9622c7b..6b94277f 100644 --- a/include/react/logging/EventLog.h +++ b/include/react/logging/EventLog.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) diff --git a/include/react/logging/EventRecords.h b/include/react/logging/EventRecords.h index 4ec91cbe..ea2359f5 100644 --- a/include/react/logging/EventRecords.h +++ b/include/react/logging/EventRecords.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) diff --git a/include/react/logging/Logging.h b/include/react/logging/Logging.h index c5546883..3f0aacd2 100644 --- a/include/react/logging/Logging.h +++ b/include/react/logging/Logging.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) diff --git a/src/engine/PulsecountEngine.cpp b/src/engine/PulsecountEngine.cpp index 1e74bd1f..5fa3a844 100644 --- a/src/engine/PulsecountEngine.cpp +++ b/src/engine/PulsecountEngine.cpp @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) diff --git a/src/engine/SubtreeEngine.cpp b/src/engine/SubtreeEngine.cpp index 9189c697..c71d6e0f 100644 --- a/src/engine/SubtreeEngine.cpp +++ b/src/engine/SubtreeEngine.cpp @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) diff --git a/src/engine/ToposortEngine.cpp b/src/engine/ToposortEngine.cpp index 3d746452..54612191 100644 --- a/src/engine/ToposortEngine.cpp +++ b/src/engine/ToposortEngine.cpp @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) diff --git a/src/logging/EventLog.cpp b/src/logging/EventLog.cpp index a22601e5..dcd8f627 100644 --- a/src/logging/EventLog.cpp +++ b/src/logging/EventLog.cpp @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) diff --git a/src/logging/EventRecords.cpp b/src/logging/EventRecords.cpp index 84ced447..3145c43a 100644 --- a/src/logging/EventRecords.cpp +++ b/src/logging/EventRecords.cpp @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) diff --git a/tests/src/EventStreamTest.cpp b/tests/src/EventStreamTest.cpp index 3714b371..6801c5e9 100644 --- a/tests/src/EventStreamTest.cpp +++ b/tests/src/EventStreamTest.cpp @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) diff --git a/tests/src/EventStreamTest.h b/tests/src/EventStreamTest.h index bb2efce4..e33653a0 100644 --- a/tests/src/EventStreamTest.h +++ b/tests/src/EventStreamTest.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) diff --git a/tests/src/EventStreamTestQ.cpp b/tests/src/EventStreamTestQ.cpp index 767a3dad..d61330d1 100644 --- a/tests/src/EventStreamTestQ.cpp +++ b/tests/src/EventStreamTestQ.cpp @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) diff --git a/tests/src/MoveTest.cpp b/tests/src/MoveTest.cpp index 81f09f31..c5963745 100644 --- a/tests/src/MoveTest.cpp +++ b/tests/src/MoveTest.cpp @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) diff --git a/tests/src/MoveTest.h b/tests/src/MoveTest.h index 46e1d39d..41eb5810 100644 --- a/tests/src/MoveTest.h +++ b/tests/src/MoveTest.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) diff --git a/tests/src/ObserverTest.cpp b/tests/src/ObserverTest.cpp index 87cb46eb..ae331812 100644 --- a/tests/src/ObserverTest.cpp +++ b/tests/src/ObserverTest.cpp @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) diff --git a/tests/src/ObserverTest.h b/tests/src/ObserverTest.h index cc07f44c..af5ac834 100644 --- a/tests/src/ObserverTest.h +++ b/tests/src/ObserverTest.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) diff --git a/tests/src/ObserverTestQ.cpp b/tests/src/ObserverTestQ.cpp index 68449272..1e36c088 100644 --- a/tests/src/ObserverTestQ.cpp +++ b/tests/src/ObserverTestQ.cpp @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) diff --git a/tests/src/OperationsTest.cpp b/tests/src/OperationsTest.cpp index 72257431..cc3b576e 100644 --- a/tests/src/OperationsTest.cpp +++ b/tests/src/OperationsTest.cpp @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) diff --git a/tests/src/OperationsTest.h b/tests/src/OperationsTest.h index 5ef9cc3d..1af27694 100644 --- a/tests/src/OperationsTest.h +++ b/tests/src/OperationsTest.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) diff --git a/tests/src/OperationsTestQ.cpp b/tests/src/OperationsTestQ.cpp index 5da10bfa..83e8a7ab 100644 --- a/tests/src/OperationsTestQ.cpp +++ b/tests/src/OperationsTestQ.cpp @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) diff --git a/tests/src/ParallelizationTest.cpp b/tests/src/ParallelizationTest.cpp index aa583c17..9ef6d156 100644 --- a/tests/src/ParallelizationTest.cpp +++ b/tests/src/ParallelizationTest.cpp @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) diff --git a/tests/src/ParallelizationTest.h b/tests/src/ParallelizationTest.h index 6c5fd1d7..43a99f05 100644 --- a/tests/src/ParallelizationTest.h +++ b/tests/src/ParallelizationTest.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) diff --git a/tests/src/SignalTest.cpp b/tests/src/SignalTest.cpp index d19239bd..44a68828 100644 --- a/tests/src/SignalTest.cpp +++ b/tests/src/SignalTest.cpp @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) diff --git a/tests/src/SignalTest.h b/tests/src/SignalTest.h index 8d7a34e2..b20eabe8 100644 --- a/tests/src/SignalTest.h +++ b/tests/src/SignalTest.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) diff --git a/tests/src/SignalTestQ.cpp b/tests/src/SignalTestQ.cpp index 6e93c730..b6bacde1 100644 --- a/tests/src/SignalTestQ.cpp +++ b/tests/src/SignalTestQ.cpp @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) diff --git a/tests/src/TestUtil.h b/tests/src/TestUtil.h index dd00efb8..a6cc5306 100644 --- a/tests/src/TestUtil.h +++ b/tests/src/TestUtil.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) diff --git a/tests/src/TransactionTest.cpp b/tests/src/TransactionTest.cpp index 61a51e11..487f7f5b 100644 --- a/tests/src/TransactionTest.cpp +++ b/tests/src/TransactionTest.cpp @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) diff --git a/tests/src/TransactionTest.h b/tests/src/TransactionTest.h index 74fc7b6c..a332de90 100644 --- a/tests/src/TransactionTest.h +++ b/tests/src/TransactionTest.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2014. +// Copyright Sebastian Jeckel 2016. // 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) From 46dee49a66e80f1909f5646b598200160205e6f3 Mon Sep 17 00:00:00 2001 From: schlangster Date: Thu, 28 Jul 2016 23:50:00 +0200 Subject: [PATCH 29/75] Refactoring WIP. --- include/react/Algorithm.h | 103 +- .../{IReactiveEngine.h => IReactiveGroup.h} | 31 +- include/react/detail/IReactiveNode.h | 9 +- include/react/detail/graph/EventNodes.h | 1025 +++++------------ include/react/detail/graph/GraphBase.h | 74 +- include/react/detail/graph/SignalNodes.h | 6 +- project/msvc/CppReact.vcxproj | 5 +- project/msvc/CppReact.vcxproj.filters | 15 +- 8 files changed, 408 insertions(+), 860 deletions(-) rename include/react/detail/{IReactiveEngine.h => IReactiveGroup.h} (68%) diff --git a/include/react/Algorithm.h b/include/react/Algorithm.h index edfca68e..b6da68af 100644 --- a/include/react/Algorithm.h +++ b/include/react/Algorithm.h @@ -22,57 +22,43 @@ /////////////////////////////////////////////////////////////////////////////////////////////////// /// Forward declarations /////////////////////////////////////////////////////////////////////////////////////////////////// -template +template class Signal; -template +template class VarSignal; -template +template class Events; -template +template class EventSource; enum class Token; -template -class SignalPack; - /////////////////////////////////////////////////////////////////////////////////////////////////// /// Hold - Hold the most recent event in a signal /////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename D, - typename V, - typename T = typename std::decay::type -> -auto Hold(const Events& events, V&& init) - -> Signal +template +auto Hold(const Events& events, V&& init) -> Signal { using REACT_IMPL::HoldNode; - return Signal( - std::make_shared>( + return Signal( + std::make_shared>( std::forward(init), GetNodePtr(events))); } /////////////////////////////////////////////////////////////////////////////////////////////////// /// Monitor - Emits value changes of target signal /////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename D, - typename S -> -auto Monitor(const Signal& target) - -> Events +template +auto Monitor(const Signal& target) -> Events { using REACT_IMPL::MonitorNode; - return Events( - std::make_shared>( + return Events( + std::make_shared>( GetNodePtr(target))); } @@ -81,14 +67,13 @@ auto Monitor(const Signal& target) /////////////////////////////////////////////////////////////////////////////////////////////////// template < - typename D, + typename S, typename E, typename V, - typename FIn, - typename S = typename std::decay::type + typename F, + > -auto Iterate(const Events& events, V&& init, FIn&& func) - -> Signal +auto Iterate(const Events& events, V&& init, F&& func) -> Signal { using REACT_IMPL::IterateNode; using REACT_IMPL::IterateByRefNode; @@ -97,7 +82,7 @@ auto Iterate(const Events& events, V&& init, FIn&& func) using REACT_IMPL::IsCallableWith; using REACT_IMPL::EventRange; - using F = typename std::decay::type; + using TFunc = typename std::decay::type; using NodeT = typename std::conditional< @@ -122,7 +107,7 @@ auto Iterate(const Events& events, V&& init, FIn&& func) ! std::is_same::value, "Iterate: Passed function does not match any of the supported signatures."); - return Signal( + return Signal( std::make_shared( std::forward(init), GetNodePtr(events), std::forward(func))); } @@ -132,16 +117,13 @@ auto Iterate(const Events& events, V&& init, FIn&& func) /////////////////////////////////////////////////////////////////////////////////////////////////// template < - typename D, + typename S, typename E, typename V, typename FIn, - typename ... TDepValues, - typename S = typename std::decay::type + typename ... TDepValues > -auto Iterate(const Events& events, V&& init, - const SignalPack& depPack, FIn&& func) - -> Signal +auto Iterate(const Events& events, V&& init, const SignalPack& depPack, FIn&& func) -> Signal { using REACT_IMPL::SyncedIterateNode; using REACT_IMPL::SyncedIterateByRefNode; @@ -211,19 +193,13 @@ auto Iterate(const Events& events, V&& init, /////////////////////////////////////////////////////////////////////////////////////////////////// /// Snapshot - Sets signal value to value of other signal when event is received /////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename D, - typename S, - typename E -> -auto Snapshot(const Events& trigger, const Signal& target) - -> Signal +template +auto Snapshot(const Events& trigger, const Signal& target) -> Signal { using REACT_IMPL::SnapshotNode; - return Signal( - std::make_shared>( + return Signal( + std::make_shared>( GetNodePtr(target), GetNodePtr(trigger))); } @@ -232,32 +208,21 @@ auto Snapshot(const Events& trigger, const Signal& target) /////////////////////////////////////////////////////////////////////////////////////////////////// /// Pulse - Emits value of target signal when event is received /////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename D, - typename S, - typename E -> -auto Pulse(const Events& trigger, const Signal& target) - -> Events +template +auto Pulse(const Events& trigger, const Signal& target) -> Events { using REACT_IMPL::PulseNode; - return Events( - std::make_shared>( + return Events( + std::make_shared>( GetNodePtr(target), GetNodePtr(trigger))); } /////////////////////////////////////////////////////////////////////////////////////////////////// /// Changed - Emits token when target signal was changed /////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename D, - typename S -> -auto Changed(const Signal& target) - -> Events +template +auto Changed(const Signal& target) -> Events { return Monitor(target).Tokenize(); } @@ -267,12 +232,10 @@ auto Changed(const Signal& target) /////////////////////////////////////////////////////////////////////////////////////////////////// template < - typename D, + typename T, typename V, - typename S = typename std::decay::type > -auto ChangedTo(const Signal& target, V&& value) - -> Events +auto ChangedTo(const Signal& target, V&& value) -> Events { return Monitor(target) .Filter([=] (const S& v) { return v == value; }) diff --git a/include/react/detail/IReactiveEngine.h b/include/react/detail/IReactiveGroup.h similarity index 68% rename from include/react/detail/IReactiveEngine.h rename to include/react/detail/IReactiveGroup.h index b4e0b83c..b86a389c 100644 --- a/include/react/detail/IReactiveEngine.h +++ b/include/react/detail/IReactiveGroup.h @@ -18,32 +18,31 @@ /***************************************/ REACT_IMPL_BEGIN /**************************************/ +using NodeId = uint; +using TurnId = uint; + /////////////////////////////////////////////////////////////////////////////////////////////////// /// IReactiveEngine /////////////////////////////////////////////////////////////////////////////////////////////////// -struct IReactiveEngine +struct IReactiveGroup { - using NodeId = uint; - using TurnId = uint; - - void OnTurnAdmissionStart(TurnId& turn) {} - void OnTurnAdmissionEnd(TurnId& turn) {} + virtual ~IReactiveGroup() = 0; - void OnInputChange(NodeId& node, TurnId& turn) {} + virtual void OnTurnAdmissionStart(TurnId turn) = 0; + virtual void OnTurnAdmissionEnd(TurnId turn) = 0; - void Propagate(TurnId& turn) {} + virtual void OnInputChange(NodeId node, TurnId turn) = 0; - void OnNodeCreate(NodeId& node) {} - void OnNodeDestroy(NodeId& node) {} + virtual void Propagate(TurnId turn) = 0; - void OnNodeAttach(NodeId node, NodeId parent) {} - void OnNodeDetach(NodeId node, NodeId parent) {} + virtual NodeId OnNodeCreate() = 0; + virtual void OnNodeDestroy(NodeId node) = 0; - void OnNodePulse(NodeId& node, TurnId& turn) {} - void OnNodeIdlePulse(NodeId& node, TurnId& turn) {} + virtual void OnNodeAttach(NodeId node, NodeId parent) = 0; + virtual void OnNodeDetach(NodeId node, NodeId parent) = 0; - void OnDynamicNodeAttach(NodeId& node, NodeId& parent, TurnId& turn) {} - void OnDynamicNodeDetach(NodeId& node, NodeId& parent, TurnId& turn) {} + virtual void OnDynamicNodeAttach(NodeId node, NodeId parent, TurnId turn) = 0; + virtual void OnDynamicNodeDetach(NodeId node, NodeId parent, TurnId turn) = 0; }; /////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/include/react/detail/IReactiveNode.h b/include/react/detail/IReactiveNode.h index 34967834..68fe08be 100644 --- a/include/react/detail/IReactiveNode.h +++ b/include/react/detail/IReactiveNode.h @@ -13,10 +13,11 @@ /***************************************/ REACT_IMPL_BEGIN /**************************************/ -enum class EUpdateResult +enum class UpdateResult { - UNCHANGED, - CHANGED + unchanged, + changed, + shifted }; /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -31,7 +32,7 @@ struct IReactiveNode // Note: Could get rid of this ugly ptr by adding a template parameter to the interface // But that would mean all engine nodes need that template parameter too - so rather cast - virtual EUpdateResult Update() = 0; + virtual UpdateResult Update() = 0; /// Input nodes can be manipulated externally. virtual bool IsInputNode() const = 0; diff --git a/include/react/detail/graph/EventNodes.h b/include/react/detail/graph/EventNodes.h index f6c750cc..00e35cbf 100644 --- a/include/react/detail/graph/EventNodes.h +++ b/include/react/detail/graph/EventNodes.h @@ -30,30 +30,23 @@ template class SignalNode; -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// BufferClearAccessPolicy -/// -/// Provides thread safe access to clear event buffer if parallel updating is enabled. -/////////////////////////////////////////////////////////////////////////////////////////////////// -// Note: Weird design due to empty base class optimization -template -struct BufferClearAccessPolicy : - private ConditionalCriticalSection -{ - template - void AccessBufferForClearing(const F& f) { this->Access(f); } -}; - /////////////////////////////////////////////////////////////////////////////////////////////////// /// EventStreamNode /////////////////////////////////////////////////////////////////////////////////////////////////// template -class EventStreamNode : public ObservableNode +class EventStreamNode : public NodeBase { public: using StorageType = std::vector; - EventStreamNode() = default; + EventStreamNode(IReactiveGroup* group) : NodeBase( group ) + { } + + EventStreamNode(NodeBase&&) = default; + EventStreamNode& operator=(NodeBase&&) = default; + + EventStreamNode(const NodeBase&) = delete; + EventStreamNode& operator=(const NodeBase&) = delete; void SetCurrentTurn(const TurnT& turn, bool forceUpdate = false, bool noClear = false) { @@ -74,43 +67,36 @@ class EventStreamNode : public ObservableNode { return events_; } protected: - StorageType events_; + StorageType events_; private: - uint curTurnId_ { (std::numeric_limits::max)() }; + uint curTurnId_ { (std::numeric_limits::max)() }; }; -template -using EventStreamNodePtrT = std::shared_ptr>; - /////////////////////////////////////////////////////////////////////////////////////////////////// /// EventSourceNode /////////////////////////////////////////////////////////////////////////////////////////////////// -template -class EventSourceNode : - public EventStreamNode, - public IInputNode +template +class EventSourceNode : public EventStreamNode, public IInputNode { public: - EventSourceNode() : - EventSourceNode::EventStreamNode{ } - { - Engine::OnNodeCreate(*this); - } + EventSourceNode(IReactiveGroup* group) : EventSourceNode::EventStreamNode( group ) + { this->RegisterMe(); } ~EventSourceNode() - { - Engine::OnNodeDestroy(*this); - } + { this->UnregisterMe(); } + + virtual const char* GetNodeType() const override + { return "EventSource"; } - virtual const char* GetNodeType() const override { return "EventSourceNode"; } - virtual bool IsInputNode() const override { return true; } - virtual int DependencyCount() const override { return 0; } + virtual bool IsInputNode() const override + { return true; } + + virtual int DependencyCount() const override + { return 0; } virtual void Update(void* turnPtr) override - { - REACT_ASSERT(false, "Ticked EventSourceNode\n"); - } + { REACT_ASSERT(false, "Updated EventSourceNode\n"); } template void AddInput(V&& v) @@ -148,416 +134,189 @@ class EventSourceNode : }; /////////////////////////////////////////////////////////////////////////////////////////////////// -/// EventOpNode +/// EventMergeNode /////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename T, - typename ... Ds -> -class EventMergeNode : public EventStreamNode +template +class EventMergeNode : public EventStreamNode { public: - template - EventMergeNode(Us&& ... args) : - EventOpNode::EventStreamNode( ), - op_( std::forward(args) ... ) + EventMergeNode(IReactiveGroup* group, const std::shared_ptr>& ... deps) : + EventMergeNode::EventStreamNode( group ), + depHolder_( deps ... ) { - Engine::OnNodeCreate(*this); - op_.template Attach(*this); + this->RegisterMe(); + REACT_EXPAND_PACK(this->AttachToMe(deps->GetNodeId())); } - ~EventOpNode() + ~EventMergeNode() { - if (!wasOpStolen_) - op_.template Detach(*this); - Engine::OnNodeDestroy(*this); + apply([this] (const auto& ... deps) { REACT_EXPAND_PACK(this->DetachFromMe(deps->GetNodeId())); }, depHolder_); + this->UnregisterMe(); } - virtual EUpdateResult Update() override + virtual UpdateResult Update() override { - using TurnT = typename D::Engine::TurnT; - TurnT& turn = *reinterpret_cast(turnPtr); - - this->SetCurrentTurn(turn, true); - - {// timer - size_t count = 0; - using TimerT = typename EventOpNode::ScopedUpdateTimer; - TimerT scopedTimer( *this, count ); + // this->SetCurrentTurn(turn, true); - op_.Collect(turn, EventCollector( this->events_ )); + apply([this] (const auto& ... deps) { REACT_EXPAND_PACK(MergeFromDep(deps)); }, depHolder_); - // Note: Count was passed by reference, so we can still change before the dtor - // of the scoped timer is called - count = this->events_.size(); - }// ~timer - - if (! this->events_.empty()) - return EUpdateResult::CHANGED; + if (! this->Events().empty()) + return UpdateResult::changed; else - return EUpdateResult::UNCHANGED; + return UpdateResult::unchanged; } virtual const char* GetNodeType() const override - { return "EventOpNode"; } + { return "EventMerge"; } virtual int DependencyCount() const override - { return TOp::dependency_count; } + { return sizeof...(Es); } private: - TOp op_; - bool wasOpStolen_ = false; -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// EventMergeOp -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename T, - typename ... Ds -> -class EventMergeOp : public ReactiveOpBase -{ -public: - template - EventMergeOp(Us&& ... deps) : - EventMergeOp::ReactiveOpBase(DontMove(), std::forward(deps) ...) - {} - - EventMergeOp(EventMergeOp&& other) = default; - - template - void Collect(const TTurn& turn, const TCollector& collector) const + template + void MergeFromDep(const std::shared_ptr& other) { - apply(CollectFunctor( turn, collector ), this->deps_); + //arg->SetCurrentTurn(turn); + this->Events().insert(this->Events().end(), other->Events().begin(), other->Events().end()); } - template - void CollectRec(const TFunctor& functor) const - { - apply(reinterpret_cast&>(functor), this->deps_); - } - -private: - template - struct CollectFunctor - { - CollectFunctor(const TTurn& turn, const TCollector& collector) : - MyTurn( turn ), - MyCollector( collector ) - {} - - void operator()(const TDeps& ... deps) const - { - REACT_EXPAND_PACK(collect(deps)); - } - - template - void collect(const T& op) const - { - op.template CollectRec(*this); - } - - template - void collect(const std::shared_ptr& depPtr) const - { - depPtr->SetCurrentTurn(MyTurn); - - for (const auto& v : depPtr->Events()) - MyCollector(v); - } - - const TTurn& MyTurn; - const TCollector& MyCollector; - }; + std::tuple ...> depHolder_; }; /////////////////////////////////////////////////////////////////////////////////////////////////// -/// EventFilterOp +/// EventTransformNode /////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename E, - typename TFilter, - typename TDep -> -class EventFilterOp : public ReactiveOpBase +template +class EventTransformNode : public EventStreamNode { public: - template - EventFilterOp(TFilterIn&& filter, TDepIn&& dep) : - EventFilterOp::ReactiveOpBase{ DontMove(), std::forward(dep) }, - filter_( std::forward(filter) ) - {} - - EventFilterOp(EventFilterOp&& other) : - EventFilterOp::ReactiveOpBase{ std::move(other) }, - filter_( std::move(other.filter_) ) - {} - - template - void Collect(const TTurn& turn, const TCollector& collector) const + template + EventTransformNode(IReactiveGroup* group, const std::shared_ptr>& dep, U&& func) : + EventTransformNode::EventStreamNode( group ), + dep_( dep ), + func_( std::forward(func) ) { - collectImpl(turn, FilteredEventCollector{ filter_, collector }, getDep()); + this->RegisterMe(); + this->AttachToMe(dep->GetNodeId()); } - template - void CollectRec(const TFunctor& functor) const + ~EventTransformNode() { - // Can't recycle functor because MyFunc needs replacing - Collect(functor.MyTurn, functor.MyCollector); + this->DetachFromMe(dep_->GetNodeId()); + this->UnregisterMe(); } -private: - const TDep& getDep() const { return std::get<0>(this->deps_); } - - template - struct FilteredEventCollector - { - FilteredEventCollector(const TFilter& filter, const TCollector& collector) : - MyFilter( filter ), - MyCollector( collector ) - {} - - void operator()(const E& e) const - { - // Accepted? - if (MyFilter(e)) - MyCollector(e); - } - - const TFilter& MyFilter; - const TCollector& MyCollector; // The wrapped collector - }; - - template - static void collectImpl(const TTurn& turn, const TCollector& collector, const T& op) + virtual UpdateResult Update() override { - op.Collect(turn, collector); - } + // this->SetCurrentTurn(turn, true); - template - static void collectImpl(const TTurn& turn, const TCollector& collector, - const std::shared_ptr& depPtr) - { - depPtr->SetCurrentTurn(turn); + for (const auto& v : dep_->Events()) + this->Events().push_back(func_(v)); - for (const auto& v : depPtr->Events()) - collector(v); + if (! this->Events().empty()) + return UpdateResult::changed; + else + return UpdateResult::unchanged; } - TFilter filter_; -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// EventTransformOp -/////////////////////////////////////////////////////////////////////////////////////////////////// -// Todo: Refactor code duplication -template -< - typename E, - typename TFunc, - typename TDep -> -class EventTransformOp : public ReactiveOpBase -{ -public: - template - EventTransformOp(TFuncIn&& func, TDepIn&& dep) : - EventTransformOp::ReactiveOpBase( DontMove(), std::forward(dep) ), - func_( std::forward(func) ) - {} - - EventTransformOp(EventTransformOp&& other) : - EventTransformOp::ReactiveOpBase( std::move(other) ), - func_( std::move(other.func_) ) - {} - - template - void Collect(const TTurn& turn, const TCollector& collector) const - { - collectImpl(turn, TransformEventCollector( func_, collector ), getDep()); - } + virtual const char* GetNodeType() const override + { return "EventTransform"; } - template - void CollectRec(const TFunctor& functor) const - { - // Can't recycle functor because MyFunc needs replacing - Collect(functor.MyTurn, functor.MyCollector); - } + virtual int DependencyCount() const override + { return 1; } private: - const TDep& getDep() const { return std::get<0>(this->deps_); } - - template - struct TransformEventCollector - { - TransformEventCollector(const TFunc& func, const TTarget& target) : - MyFunc( func ), - MyTarget( target ) - {} - - void operator()(const E& e) const - { - MyTarget(MyFunc(e)); - } + std::shared_ptr dep_; - const TFunc& MyFunc; - const TTarget& MyTarget; - }; - - template - static void collectImpl(const TTurn& turn, const TCollector& collector, const T& op) - { - op.Collect(turn, collector); - } - - template - static void collectImpl(const TTurn& turn, const TCollector& collector, const std::shared_ptr& depPtr) - { - depPtr->SetCurrentTurn(turn); - - for (const auto& v : depPtr->Events()) - collector(v); - } - - TFunc func_; + F func_; }; /////////////////////////////////////////////////////////////////////////////////////////////////// -/// EventOpNode +/// EventFilterNode /////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename D, - typename E, - typename TOp -> -class EventOpNode : - public EventStreamNode +template +class EventFilterNode : public EventStreamNode { - using Engine = typename EventOpNode::Engine; - public: - template - EventOpNode(TArgs&& ... args) : - EventOpNode::EventStreamNode( ), - op_( std::forward(args) ... ) + template + EventFilterNode(IReactiveGroup* group, const std::shared_ptr>& dep, U&& pred) : + EventFilterNode::EventStreamNode( group ), + dep_( dep ), + pred_( std::forward(pred) ) { - Engine::OnNodeCreate(*this); - op_.template Attach(*this); + this->RegisterMe(); + this->AttachToMe(dep->GetNodeId()); } - ~EventOpNode() + ~EventFilterNode() { - if (!wasOpStolen_) - op_.template Detach(*this); - Engine::OnNodeDestroy(*this); + this->DetachFromMe(dep_->GetNodeId()); + this->UnregisterMe(); } - virtual void Update(void* turnPtr) override + virtual UpdateResult Update() override { - using TurnT = typename D::Engine::TurnT; - TurnT& turn = *reinterpret_cast(turnPtr); - - this->SetCurrentTurn(turn, true); + // this->SetCurrentTurn(turn, true); - REACT_LOG(D::Log().template Append( - GetObjectId(*this), turn.Id())); + for (const auto& v : dep_->Events()) + if (pred_(v)) + this->Events().push_back(v); - {// timer - size_t count = 0; - using TimerT = typename EventOpNode::ScopedUpdateTimer; - TimerT scopedTimer( *this, count ); - - op_.Collect(turn, EventCollector( this->events_ )); - - // Note: Count was passed by reference, so we can still change before the dtor - // of the scoped timer is called - count = this->events_.size(); - }// ~timer - - REACT_LOG(D::Log().template Append( - GetObjectId(*this), turn.Id())); - - if (! this->events_.empty()) - Engine::OnNodePulse(*this, turn); + if (! this->Events().empty()) + return UpdateResult::changed; else - Engine::OnNodeIdlePulse(*this, turn); + return UpdateResult::unchanged; } - virtual const char* GetNodeType() const override { return "EventOpNode"; } - virtual int DependencyCount() const override { return TOp::dependency_count; } + virtual const char* GetNodeType() const override + { return "EventFilter"; } - TOp StealOp() - { - REACT_ASSERT(wasOpStolen_ == false, "Op was already stolen."); - wasOpStolen_ = true; - op_.template Detach(*this); - return std::move(op_); - } + virtual int DependencyCount() const override + { return 1; } private: - struct EventCollector - { - using DataT = typename EventOpNode::DataT; - - EventCollector(DataT& events) : MyEvents( events ) {} - - void operator()(const E& e) const { MyEvents.push_back(e); } + std::shared_ptr dep_; - DataT& MyEvents; - }; - - TOp op_; - bool wasOpStolen_ = false; + F pred_; }; /////////////////////////////////////////////////////////////////////////////////////////////////// /// EventFlattenNode /////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename D, - typename TOuter, - typename TInner -> -class EventFlattenNode : public EventStreamNode +template +class EventFlattenNode : public EventStreamNode { - using Engine = typename EventFlattenNode::Engine; - public: - EventFlattenNode(const std::shared_ptr>& outer, - const std::shared_ptr>& inner) : - EventFlattenNode::EventStreamNode( ), + EventFlattenNode(IReactiveGroup* group, const std::shared_ptr>& outer, const std::shared_ptr>& inner) : + EventFlattenNode::EventStreamNode( group ), outer_( outer ), inner_( inner ) { - Engine::OnNodeCreate(*this); - Engine::OnNodeAttach(*this, *outer_); - Engine::OnNodeAttach(*this, *inner_); + this->RegisterMe(); + this->AttachToMe(outer->GetNodeId()); + this->AttachToMe(inner->GetNodeId()); } ~EventFlattenNode() { - Engine::OnNodeDetach(*this, *outer_); - Engine::OnNodeDetach(*this, *inner_); - Engine::OnNodeDestroy(*this); + this->DetachFromMe(inner->GetNodeId()); + this->DetachFromMe(outer->GetNodeId()); + this->UnregisterMe(); } - virtual const char* GetNodeType() const override { return "EventFlattenNode"; } - virtual bool IsDynamicNode() const override { return true; } - virtual int DependencyCount() const override { return 2; } + virtual const char* GetNodeType() const override + { return "EventFlatten"; } - virtual void Update(void* turnPtr) override - { - typedef typename D::Engine::TurnT TurnT; - TurnT& turn = *reinterpret_cast(turnPtr); + virtual bool IsDynamicNode() const override + { return true; } - this->SetCurrentTurn(turn, true); - inner_->SetCurrentTurn(turn); + virtual int DependencyCount() const override + { return 2; } + + virtual UpdateResult Update() override + { + // this->SetCurrentTurn(turn, true); + // inner_->SetCurrentTurn(turn); auto newInner = GetNodePtr(outer_->ValueRef()); @@ -569,285 +328,180 @@ class EventFlattenNode : public EventStreamNode auto oldInner = inner_; inner_ = newInner; - Engine::OnDynamicNodeDetach(*this, *oldInner, turn); - Engine::OnDynamicNodeAttach(*this, *newInner, turn); + this->DynamicDetachFromMe(oldInner->GetNodeId(), 0); + this->DynamicAttachToMe(newInner->GetNodeId(), 0); - return; + return UpdateResult::shifted; } - REACT_LOG(D::Log().template Append( - GetObjectId(*this), turn.Id())); + this->Events().insert(this->Events().end(), inner_->Events().begin(), inner_->Events().end()); - this->events_.insert( - this->events_.end(), - inner_->Events().begin(), - inner_->Events().end()); - - REACT_LOG(D::Log().template Append( - GetObjectId(*this), turn.Id())); - - if (this->events_.size() > 0) - Engine::OnNodePulse(*this, turn); + if (! this->Events().empty()) + return UpdateResult::changed; else - Engine::OnNodeIdlePulse(*this, turn); + return UpdateResult::unchanged; } private: - std::shared_ptr> outer_; - std::shared_ptr> inner_; + std::shared_ptr> outer_; + std::shared_ptr> inner_; }; /////////////////////////////////////////////////////////////////////////////////////////////////// /// SyncedEventTransformNode /////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename D, - typename TIn, - typename TOut, - typename TFunc, - typename ... TDepValues -> -class SyncedEventTransformNode : - public EventStreamNode +template +class SyncedEventTransformNode : public EventStreamNode { - using Engine = typename SyncedEventTransformNode::Engine; - public: - template - SyncedEventTransformNode(const std::shared_ptr>& source, F&& func, - const std::shared_ptr>& ... deps) : - SyncedEventTransformNode::EventStreamNode( ), - source_( source ), - func_( std::forward(func) ), - deps_( deps ... ) + template + SyncedEventTransformNode(IReactiveGroup* group, const std::shared_ptr>& dep, U&& func, const std::shared_ptr>& ... syncs) : + SyncedEventTransformNode::EventStreamNode( group ), + dep_( dep ), + func_( std::forward(func) ), + syncs_( syncs ... ) { - Engine::OnNodeCreate(*this); - Engine::OnNodeAttach(*this, *source); - REACT_EXPAND_PACK(Engine::OnNodeAttach(*this, *deps)); + this->RegisterMe(); + this->AttachToMe(dep->GetNodeId()); + REACT_EXPAND_PACK(this->AttachToMe(syncs->GetNodeId())); } ~SyncedEventTransformNode() { - Engine::OnNodeDetach(*this, *source_); - - apply( - DetachFunctor>...>( *this ), - deps_); - - Engine::OnNodeDestroy(*this); + apply([this] (const auto& ... syncs) { REACT_EXPAND_PACK(this->DetachFromMe(syncs->GetNodeId())); }, syncHolder_); + this->DetachFromMe(dep_->GetNodeId()); + this->UnregisterMe(); } - virtual void Update(void* turnPtr) override + virtual UpdateResult Update() override { - using TurnT = typename D::Engine::TurnT; - TurnT& turn = *reinterpret_cast(turnPtr); + //this->SetCurrentTurn(turn, true); - this->SetCurrentTurn(turn, true); // Update of this node could be triggered from deps, // so make sure source doesnt contain events from last turn - source_->SetCurrentTurn(turn); - - REACT_LOG(D::Log().template Append( - GetObjectId(*this), turn.Id())); - - // Don't time if there is nothing to do - if (! source_->Events().empty()) - {// timer - using TimerT = typename SyncedEventTransformNode::ScopedUpdateTimer; - TimerT scopedTimer( *this, source_->Events().size() ); - - for (const auto& e : source_->Events()) - this->events_.push_back(apply( - [this, &e] (const std::shared_ptr>& ... args) - { - return func_(e, args->ValueRef() ...); - }, - deps_)); - - }// ~timer - - REACT_LOG(D::Log().template Append( - GetObjectId(*this), turn.Id())); - - if (! this->events_.empty()) - Engine::OnNodePulse(*this, turn); + // source_->SetCurrentTurn(turn); + + for (const auto& e : dep_->Events()) + this->Events().push_back(apply([this, &e] (const auto& ... syncs) { return this->func_(e, syncs->ValueRef() ...); }, syncHolder_)); + + if (! this->Events().empty()) + return UpdateResult::changed; else - Engine::OnNodeIdlePulse(*this, turn); + return UpdateResult::unchanged; } - virtual const char* GetNodeType() const override { return "SyncedEventTransformNode"; } - virtual int DependencyCount() const override { return 1 + sizeof...(TDepValues); } + virtual const char* GetNodeType() const override + { return "SyncedEventTransform"; } + + virtual int DependencyCount() const override + { return 1 + sizeof...(TSyncs); } private: - using DepHolderT = std::tuple>...>; + std::shared_ptr> dep_; - std::shared_ptr> source_; + F func_; - TFunc func_; - DepHolderT deps_; + std::tuple>...> syncHolder_; }; /////////////////////////////////////////////////////////////////////////////////////////////////// /// SyncedEventFilterNode /////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename D, - typename E, - typename TFunc, - typename ... TDepValues -> -class SyncedEventFilterNode : - public EventStreamNode +template +class SyncedEventFilterNode : public EventStreamNode { - using Engine = typename SyncedEventFilterNode::Engine; - public: - template - SyncedEventFilterNode(const std::shared_ptr>& source, F&& filter, - const std::shared_ptr>& ... deps) : - SyncedEventFilterNode::EventStreamNode( ), - source_( source ), - filter_( std::forward(filter) ), - deps_(deps ... ) + template + SyncedEventFilterNode(IReactiveGroup* group, const std::shared_ptr>& dep, U&& pred, const std::shared_ptr>& ... syncs) : + SyncedEventFilterNode::EventStreamNode( group ), + dep_( dep ), + pred_( std::forward(pred) ), + syncs_( syncs ... ) { - Engine::OnNodeCreate(*this); - Engine::OnNodeAttach(*this, *source); - REACT_EXPAND_PACK(Engine::OnNodeAttach(*this, *deps)); + this->RegisterMe(); + this->AttachToMe(dep->GetNodeId()); + REACT_EXPAND_PACK(this->AttachToMe(syncs->GetNodeId())); } ~SyncedEventFilterNode() { - Engine::OnNodeDetach(*this, *source_); - - apply( - DetachFunctor>...>( *this ), - deps_); - - Engine::OnNodeDestroy(*this); + apply([this] (const auto& ... syncs) { REACT_EXPAND_PACK(this->DetachFromMe(syncs->GetNodeId())); }, syncHolder_); + this->DetachFromMe(dep_->GetNodeId()); + this->UnregisterMe(); } - virtual void Update(void* turnPtr) override + virtual UpdateResult Update() override { - using TurnT = typename D::Engine::TurnT; - TurnT& turn = *reinterpret_cast(turnPtr); + // this->SetCurrentTurn(turn, true); - this->SetCurrentTurn(turn, true); // Update of this node could be triggered from deps, // so make sure source doesnt contain events from last turn - source_->SetCurrentTurn(turn); - - REACT_LOG(D::Log().template Append( - GetObjectId(*this), turn.Id())); - - // Don't time if there is nothing to do - if (! source_->Events().empty()) - {// timer - using TimerT = typename SyncedEventFilterNode::ScopedUpdateTimer; - TimerT scopedTimer( *this, source_->Events().size() ); - - for (const auto& e : source_->Events()) - if (apply( - [this, &e] (const std::shared_ptr>& ... args) - { - return filter_(e, args->ValueRef() ...); - }, - deps_)) - this->events_.push_back(e); - }// ~timer - - REACT_LOG(D::Log().template Append( - GetObjectId(*this), turn.Id())); - - if (! this->events_.empty()) - Engine::OnNodePulse(*this, turn); + //source_->SetCurrentTurn(turn); + + for (const auto& e : dep_->Events()) + if (apply([this, &e] (const auto& ... syncs) { return this->func_(e, syncs->ValueRef() ...); }, syncHolder_)) + this->Events().push_back(e); + + if (! this->Events().empty()) + return UpdateResult::changed; else - Engine::OnNodeIdlePulse(*this, turn); + return UpdateResult::unchanged; } - virtual const char* GetNodeType() const override { return "SyncedEventFilterNode"; } - virtual int DependencyCount() const override { return 1 + sizeof...(TDepValues); } + virtual const char* GetNodeType() const override + { return "SyncedEventFilter"; } - virtual bool IsHeavyweight() const override - { - return this->IsUpdateThresholdExceeded(); - } + virtual int DependencyCount() const override + { return 1 + sizeof...(TSyncs); } private: - using DepHolderT = std::tuple>...>; + std::shared_ptr> dep_; - std::shared_ptr> source_; + F pred_; - TFunc filter_; - DepHolderT deps_; + std::tuple>...> syncHolder_; }; /////////////////////////////////////////////////////////////////////////////////////////////////// /// EventProcessingNode /////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename D, - typename TIn, - typename TOut, - typename TFunc -> -class EventProcessingNode : - public EventStreamNode +template +class EventProcessingNode : public EventStreamNode { - using Engine = typename EventProcessingNode::Engine; - public: - template - EventProcessingNode(const std::shared_ptr>& source, F&& func) : - EventProcessingNode::EventStreamNode( ), - source_( source ), - func_( std::forward(func) ) + template + EventProcessingNode(IReactiveGroup* group, const std::shared_ptr>& dep, U&& func) : + EventProcessingNode::EventStreamNode( group ), + dep_( dep ), + func_( std::forward(func) ) { - Engine::OnNodeCreate(*this); - Engine::OnNodeAttach(*this, *source); + this->RegisterMe(); + this->AttachToMe(dep->GetNodeId()); } ~EventProcessingNode() { - Engine::OnNodeDetach(*this, *source_); - Engine::OnNodeDestroy(*this); + this->DetachFromMe(dep_->GetNodeId()); + this->UnregisterMe(); } - virtual void Update(void* turnPtr) override + virtual UpdateResult Update() override { - using TurnT = typename D::Engine::TurnT; - TurnT& turn = *reinterpret_cast(turnPtr); - - this->SetCurrentTurn(turn, true); - - REACT_LOG(D::Log().template Append( - GetObjectId(*this), turn.Id())); - - {// timer - using TimerT = typename EventProcessingNode::ScopedUpdateTimer; - TimerT scopedTimer( *this, source_->Events().size() ); - - func_( - EventRange( source_->Events() ), - std::back_inserter(this->events_)); - - }// ~timer + //this->SetCurrentTurn(turn, true); - REACT_LOG(D::Log().template Append( - GetObjectId(*this), turn.Id())); + func_(EventRange( source_->Events() ), std::back_inserter(this->Events())); - if (! this->events_.empty()) - Engine::OnNodePulse(*this, turn); + if (! this->Events().empty()) + return UpdateResult::changed; else - Engine::OnNodeIdlePulse(*this, turn); + return UpdateResult::unchanged; } - virtual const char* GetNodeType() const override { return "EventProcessingNode"; } - virtual int DependencyCount() const override { return 1; } + virtual const char* GetNodeType() const override + { return "EventProcessing"; } + + virtual int DependencyCount() const override + { return 1; } private: std::shared_ptr> source_; @@ -858,224 +512,155 @@ class EventProcessingNode : /////////////////////////////////////////////////////////////////////////////////////////////////// /// SyncedEventProcessingNode /////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename D, - typename TIn, - typename TOut, - typename TFunc, - typename ... TDepValues -> -class SyncedEventProcessingNode : - public EventStreamNode +template +class SyncedEventProcessingNode : public EventStreamNode { - using Engine = typename SyncedEventProcessingNode::Engine; - public: - template - SyncedEventProcessingNode(const std::shared_ptr>& source, F&& func, - const std::shared_ptr>& ... deps) : - SyncedEventProcessingNode::EventStreamNode( ), - source_( source ), - func_( std::forward(func) ), - deps_( deps ... ) + template + SyncedEventProcessingNode(IReactiveGroup* group, const std::shared_ptr>& dep, U&& func, const std::shared_ptr>& ... syncs) : + SyncedEventProcessingNode::EventStreamNode( group ), + dep_( dep ), + func_( std::forward(func) ), + syncs_( syncs ... ) { - Engine::OnNodeCreate(*this); - Engine::OnNodeAttach(*this, *source); - REACT_EXPAND_PACK(Engine::OnNodeAttach(*this, *deps)); + this->RegisterMe(); + this->AttachToMe(dep->GetNodeId()); + REACT_EXPAND_PACK(this->AttachToMe(syncs->GetNodeId())); } ~SyncedEventProcessingNode() { - Engine::OnNodeDetach(*this, *source_); - - apply( - DetachFunctor>...>( *this ), - deps_); - - Engine::OnNodeDestroy(*this); + apply([this] (const auto& ... syncs) { REACT_EXPAND_PACK(this->DetachFromMe(syncs->GetNodeId())); }, syncHolder_); + this->DetachFromMe(dep_->GetNodeId()); + this->UnregisterMe(); } - virtual void Update(void* turnPtr) override + virtual UpdateResult Update() override { - using TurnT = typename D::Engine::TurnT; - TurnT& turn = *reinterpret_cast(turnPtr); - - this->SetCurrentTurn(turn, true); + //this->SetCurrentTurn(turn, true); // Update of this node could be triggered from deps, // so make sure source doesnt contain events from last turn - source_->SetCurrentTurn(turn); + //source_->SetCurrentTurn(turn); - REACT_LOG(D::Log().template Append( - GetObjectId(*this), turn.Id())); - - // Don't time if there is nothing to do - if (! source_->Events().empty()) - {// timer - using TimerT = typename SyncedEventProcessingNode::ScopedUpdateTimer; - TimerT scopedTimer( *this, source_->Events().size() ); - - apply( - [this] (const std::shared_ptr>& ... args) - { - func_( - EventRange( source_->Events() ), - std::back_inserter(this->events_), - args->ValueRef() ...); - }, - deps_); - - }// ~timer - - REACT_LOG(D::Log().template Append( - GetObjectId(*this), turn.Id())); + apply( + [this] (const auto& ... syncs) + { + func_(EventRange( source_->Events() ), std::back_inserter(this->Events()), syncs->ValueRef() ...); + }, + syncHolder_); - if (! this->events_.empty()) - Engine::OnNodePulse(*this, turn); + if (! this->Events().empty()) + return UpdateResult::changed; else - Engine::OnNodeIdlePulse(*this, turn); + return UpdateResult::unchanged; } - virtual const char* GetNodeType() const override { return "SycnedEventProcessingNode"; } - virtual int DependencyCount() const override { return 1 + sizeof...(TDepValues); } + virtual const char* GetNodeType() const override + { return "SycnedEventProcessing"; } + + virtual int DependencyCount() const override + { return 1 + sizeof...(TSyncs); } private: - using DepHolderT = std::tuple>...>; + std::shared_ptr> dep_; - std::shared_ptr> source_; + F func_; - TFunc func_; - DepHolderT deps_; + std::tuple>...> syncHolder_; }; /////////////////////////////////////////////////////////////////////////////////////////////////// /// EventJoinNode /////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename D, - typename ... TValues -> -class EventJoinNode : - public EventStreamNode> +template +class EventJoinNode : public EventStreamNode> { - using Engine = typename EventJoinNode::Engine; - using TurnT = typename Engine::TurnT; - public: - EventJoinNode(const std::shared_ptr>& ... sources) : - EventJoinNode::EventStreamNode( ), - slots_( sources ... ) + EventJoinNode(IReactiveGroup* group, const std::shared_ptr>& ... deps) : + EventJoinNode::EventStreamNode( group ), + slots_( deps ... ) { - Engine::OnNodeCreate(*this); - REACT_EXPAND_PACK(Engine::OnNodeAttach(*this, *sources)); + this->RegisterMe(); + REACT_EXPAND_PACK(this->AttachToMe(deps->GetNodeId())); } ~EventJoinNode() { - apply( - [this] (Slot& ... slots) { - REACT_EXPAND_PACK(Engine::OnNodeDetach(*this, *slots.Source)); - }, - slots_); - - Engine::OnNodeDestroy(*this); + apply([this] (const auto& ... slots) { REACT_EXPAND_PACK(this->DetachFromMe(slots.source->GetNodeId())); }, slots_); + this->UnregisterMe(); } - virtual void Update(void* turnPtr) override + virtual UpdateResult Update() override { - TurnT& turn = *reinterpret_cast(turnPtr); + //this->SetCurrentTurn(turn, true); - this->SetCurrentTurn(turn, true); + // Move events into buffers + apply([this, &turn] (Slot& ... slots) { REACT_EXPAND_PACK(FetchBuffer(turn, slots)); }, slots_); - REACT_LOG(D::Log().template Append( - GetObjectId(*this), turn.Id())); - - // Don't time if there is nothing to do - {// timer - size_t count = 0; - using TimerT = typename EventJoinNode::ScopedUpdateTimer; - TimerT scopedTimer( *this, count ); + while (true) + { + bool isReady = true; - // Move events into buffers + // All slots ready? apply( - [this, &turn] (Slot& ... slots) { - REACT_EXPAND_PACK(fetchBuffer(turn, slots)); + [this,&isReady] (Slot& ... slots) { + // Todo: combine return values instead + REACT_EXPAND_PACK(CheckSlot(slots, isReady)); }, slots_); - while (true) - { - bool isReady = true; - - // All slots ready? - apply( - [this,&isReady] (Slot& ... slots) { - // Todo: combine return values instead - REACT_EXPAND_PACK(checkSlot(slots, isReady)); - }, - slots_); - - if (!isReady) - break; - - // Pop values from buffers and emit tuple - apply( - [this] (Slot& ... slots) { - this->events_.emplace_back(slots.Buffer.front() ...); - REACT_EXPAND_PACK(slots.Buffer.pop_front()); - }, - slots_); - } - - count = this->events_.size(); - - }// ~timer + if (!isReady) + break; - REACT_LOG(D::Log().template Append( - GetObjectId(*this), turn.Id())); + // Pop values from buffers and emit tuple + apply( + [this] (Slot& ... slots) + { + this->Events().emplace_back(slots.buffer.front() ...); + REACT_EXPAND_PACK(slots.buffer.pop_front()); + }, + slots_); + } - if (! this->events_.empty()) - Engine::OnNodePulse(*this, turn); + if (! this->Events().empty()) + return UpdateResult::changed; else - Engine::OnNodeIdlePulse(*this, turn); + return UpdateResult::unchanged; } - virtual const char* GetNodeType() const override { return "EventJoinNode"; } - virtual int DependencyCount() const override { return sizeof...(TValues); } + virtual const char* GetNodeType() const override + { return "EventJoin"; } + + virtual int DependencyCount() const override + { return sizeof...(Ts); } private: - template + template struct Slot { - Slot(const std::shared_ptr>& src) : - Source( src ) - {} + Slot(const std::shared_ptr>& src) : + source( src ) + { } - std::shared_ptr> Source; - std::deque Buffer; + std::shared_ptr> source; + std::deque buffer; }; - template - static void fetchBuffer(TurnT& turn, Slot& slot) + template + static void FetchBuffer(TurnT& turn, Slot& slot) { - slot.Source->SetCurrentTurn(turn); - - slot.Buffer.insert( - slot.Buffer.end(), - slot.Source->Events().begin(), - slot.Source->Events().end()); + //slot.Source->SetCurrentTurn(turn); + slot.buffer.insert(slot.buffer.end(), slot.source->Events().begin(), slot.source->Events().end()); } template - static void checkSlot(Slot& slot, bool& isReady) + static void CheckSlot(Slot& slot, bool& isReady) { - auto t = isReady && !slot.Buffer.empty(); + bool t = isReady && !slot.buffer.empty(); isReady = t; } - std::tuple...> slots_; + std::tuple...> slots_; }; /****************************************/ REACT_IMPL_END /***************************************/ diff --git a/include/react/detail/graph/GraphBase.h b/include/react/detail/graph/GraphBase.h index 66993500..404108d0 100644 --- a/include/react/detail/graph/GraphBase.h +++ b/include/react/detail/graph/GraphBase.h @@ -17,7 +17,8 @@ #include "react/common/Util.h" #include "react/common/Timing.h" #include "react/common/Types.h" -#include "react/detail/IReactiveEngine.h" +#include "react/detail/IReactiveGroup.h" +#include "react/detail/IReactiveNode.h" #include "react/detail/ObserverBase.h" /***************************************/ REACT_IMPL_BEGIN /**************************************/ @@ -84,28 +85,28 @@ struct DepCounter /////////////////////////////////////////////////////////////////////////////////////////////////// /// NodeBase /////////////////////////////////////////////////////////////////////////////////////////////////// -template -class NodeBase : - public D::Policy::Engine::NodeT, - public UpdateTimingPolicy +class NodeBase : public IReactiveNode { public: - using DomainT = D; - using Policy = typename D::Policy; - using Engine = typename D::Engine; - using NodeT = typename Engine::NodeT; - using TurnT = typename Engine::TurnT; + NodeBase(IReactiveGroup* group) : group_( group ) + { } - NodeBase() = default; - - // Nodes can't be copied + NodeBase(NodeBase&&) = delete; + NodeBase& operator=(NodeBase&&) = delete; NodeBase(const NodeBase&) = delete; + NodeBase& operator=(const NodeBase&) = delete; - virtual bool IsInputNode() const override { return false; } - virtual bool IsOutputNode() const override { return false; } - virtual bool IsDynamicNode() const override { return false; } + virtual bool IsInputNode() const override + { return false; } + + virtual bool IsOutputNode() const override + { return false; } + + virtual bool IsDynamicNode() const override + { return false; } - virtual bool IsHeavyweight() const override { return this->IsUpdateThresholdExceeded(); } + virtual bool IsHeavyweight() const override + { return false; } void SetWeightHint(WeightHint weight) { @@ -122,27 +123,38 @@ class NodeBase : break; } } -}; -template -using NodeBasePtrT = std::shared_ptr>; + NodeId GetNodeId() const + { return nodeId_; } -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// ObservableNode -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -class ObservableNode : - public NodeBase, - public Observable -{ -public: - ObservableNode() = default; +protected: + void RegisterMe() + { nodeId_ = group_->RegisterNode(); } + + void UnregisterMe() + { group_->UnregisterNode(nodeId_); } + + void AttachToMe(NodeId otherNodeId) + { group_->OnNodeAttach(nodeId_, otherNodeId); } + + void DetachFromMe(NodeId otherNodeId) + { group_->OnNodeDetach(nodeId_, otherNodeId); } + + void DynamicAttachToMe(NodeId otherNodeId, TurnId turnId) + { group_->OnDynamicNodeAttach(nodeId_, otherNodeId, turnId); } + + void DynamicDetachFromMe(NodeId otherNodeId, TurnId turnId) + { group_->OnDynamicNodeDetach(nodeId_, otherNodeId, turnId); } + +private: + NodeId nodeId_; + IReactiveGroup* group_; }; /////////////////////////////////////////////////////////////////////////////////////////////////// /// Attach/detach helper functors /////////////////////////////////////////////////////////////////////////////////////////////////// -template +template struct AttachFunctor { AttachFunctor(TNode& node) : MyNode( node ) {} diff --git a/include/react/detail/graph/SignalNodes.h b/include/react/detail/graph/SignalNodes.h index 9ea74832..8f9424dc 100644 --- a/include/react/detail/graph/SignalNodes.h +++ b/include/react/detail/graph/SignalNodes.h @@ -27,14 +27,14 @@ bool Equals(const L& lhs, const R& rhs); /////////////////////////////////////////////////////////////////////////////////////////////////// /// SignalNode /////////////////////////////////////////////////////////////////////////////////////////////////// -template +template class SignalNode : public ObservableNode { public: SignalNode() = default; - template - explicit SignalNode(T&& value) : + template + explicit SignalNode(U&& value) : SignalNode::ObservableNode( ), value_( std::forward(value) ) {} diff --git a/project/msvc/CppReact.vcxproj b/project/msvc/CppReact.vcxproj index d9782c0d..f2e9c00c 100644 --- a/project/msvc/CppReact.vcxproj +++ b/project/msvc/CppReact.vcxproj @@ -159,7 +159,6 @@ - @@ -167,9 +166,8 @@ - - + @@ -189,7 +187,6 @@ - diff --git a/project/msvc/CppReact.vcxproj.filters b/project/msvc/CppReact.vcxproj.filters index 7de3201b..2b7a6008 100644 --- a/project/msvc/CppReact.vcxproj.filters +++ b/project/msvc/CppReact.vcxproj.filters @@ -57,9 +57,6 @@ Header Files\common - - Header Files - Header Files\engine @@ -69,9 +66,6 @@ Header Files\detail - - Header Files\detail - Header Files\detail @@ -81,9 +75,6 @@ Header Files\detail\graph - - Header Files\detail\graph - Header Files\detail\graph @@ -141,15 +132,15 @@ Header Files\engine - - Header Files\detail\graph - Header Files\common Header Files\detail + + Header Files\detail + From d13b3f47f8ebfcbd8062ecbfdd51db60796b885d Mon Sep 17 00:00:00 2001 From: schlangster Date: Thu, 4 Aug 2016 16:16:05 +0200 Subject: [PATCH 30/75] Major redesign WIP. --- examples/src/BasicSignals.cpp | 37 +- include/react/API.h | 118 ++++ include/react/Algorithm.h | 22 +- include/react/Event.h | 465 ++++++++------- include/react/{Domain.h => Group.h} | 210 ++++--- include/react/Observer.h | 6 +- include/react/Signal.h | 321 ++++++---- include/react/TypeTraits.h | 92 --- include/react/common/Containers.h | 148 +++++ include/react/common/TopoQueue.h | 20 +- include/react/common/Util.h | 52 +- include/react/detail/Defs.h | 13 - include/react/detail/DomainBase.h | 265 --------- include/react/detail/EventBase.h | 49 -- include/react/detail/IReactiveGraph.h | 100 ++++ include/react/detail/IReactiveGroup.h | 64 -- include/react/detail/IReactiveNode.h | 67 --- include/react/detail/ReactiveBase.h | 158 ----- include/react/detail/ReactiveInput.h | 12 +- include/react/detail/SignalBase.h | 65 -- include/react/detail/graph/AlgorithmNodes.h | 553 +++++++----------- .../react/detail/graph/ContinuationNodes.h | 351 ----------- include/react/detail/graph/EventNodes.h | 418 ++++--------- include/react/detail/graph/GraphBase.h | 238 +------- include/react/detail/graph/ObserverNodes.h | 338 +++-------- include/react/detail/graph/PropagationMT.h | 0 include/react/detail/graph/PropagationST.h | 284 +++++++++ include/react/detail/graph/ReactorNodes.h | 259 -------- include/react/detail/graph/SignalNodes.h | 346 ++++------- include/react/engine/PulsecountEngine.h | 6 +- include/react/engine/SubtreeEngine.h | 6 +- include/react/engine/ToposortEngine.h | 6 +- project/msvc/CppReact.vcxproj | 19 +- project/msvc/CppReact.vcxproj.filters | 81 +-- src/engine/PulsecountEngine.cpp | 6 +- src/engine/SubtreeEngine.cpp | 6 +- src/engine/ToposortEngine.cpp | 6 +- 37 files changed, 1920 insertions(+), 3287 deletions(-) create mode 100644 include/react/API.h rename include/react/{Domain.h => Group.h} (52%) delete mode 100644 include/react/TypeTraits.h delete mode 100644 include/react/detail/DomainBase.h delete mode 100644 include/react/detail/EventBase.h create mode 100644 include/react/detail/IReactiveGraph.h delete mode 100644 include/react/detail/IReactiveGroup.h delete mode 100644 include/react/detail/IReactiveNode.h delete mode 100644 include/react/detail/ReactiveBase.h delete mode 100644 include/react/detail/SignalBase.h delete mode 100644 include/react/detail/graph/ContinuationNodes.h create mode 100644 include/react/detail/graph/PropagationMT.h create mode 100644 include/react/detail/graph/PropagationST.h delete mode 100644 include/react/detail/graph/ReactorNodes.h diff --git a/examples/src/BasicSignals.cpp b/examples/src/BasicSignals.cpp index a5a82445..7f6943f2 100644 --- a/examples/src/BasicSignals.cpp +++ b/examples/src/BasicSignals.cpp @@ -11,10 +11,8 @@ #include #include -#include "react/Domain.h" #include "react/Signal.h" -#include "react/Observer.h" - +/* /////////////////////////////////////////////////////////////////////////////////////////////////// /// Example 1 - Hello world /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -26,7 +24,7 @@ namespace example1 // 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) + ReactiveGroup // Define type aliases for the given domain in this namespace. // Now we can use VarSignalT instead of D::VarSignalT. @@ -41,8 +39,8 @@ namespace example1 namespace v1 { // The two words - VarSignalT firstWord = MakeVar(string("Change")); - VarSignalT secondWord = MakeVar(string("me!")); + VarSignalT firstWord( string("Change") ); + VarSignalT secondWord( string("me!") ); SignalT bothWords = MakeSignal(With(firstWord,secondWord), concatFunc); @@ -388,5 +386,32 @@ int main() example5::v2::Run(); example5::v3::Run(); + return 0; +} + +*/ + +using namespace react; + +int main() +{ + auto group = ReactiveGroup( ); + + auto sig1 = VarSignal( 1, group ); + auto sig2 = VarSignal( 2, group ); + + sig1.Set(1); + sig1 <<= 1; + + sig2.Modify([] (int& value) { value = 3; }); + + group.DoTransaction( + [&] + { + sig1 <<= 2; + }); + + auto sig3 = Signal( [] (auto a, auto b) { return a + b; }, sig1, sig2 ); + return 0; } \ No newline at end of file diff --git a/include/react/API.h b/include/react/API.h new file mode 100644 index 00000000..b445b74c --- /dev/null +++ b/include/react/API.h @@ -0,0 +1,118 @@ + +// Copyright Sebastian Jeckel 2016. +// 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) + +#ifndef REACT_API_H_INCLUDED +#define REACT_API_H_INCLUDED + +#pragma once + +#include "react/detail/Defs.h" +#include "react/common/Util.h" + +/*****************************************/ REACT_BEGIN /*****************************************/ + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// API constants +/////////////////////////////////////////////////////////////////////////////////////////////////// +enum OwnershipPolicy +{ + unique, + shared +}; + +enum ThreadingPolicy +{ + sequential, + concurrent +}; + +enum class WeightHint +{ + automatic, + light, + heavy +}; + +enum class TransactionFlags +{ + none = 1 << 0, + allow_merging = 1 << 1 +}; + +REACT_DEFINE_BITMASK_OPERATORS(TransactionFlags) + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// API types +/////////////////////////////////////////////////////////////////////////////////////////////////// + +// Groups +template +class ReactiveGroup; + +// Signals +template +class SignalBase; + +template +class VarSignalBase; + +template +class Signal; + +template +class VarSignal; + +// Events +template +class EventBase; + +template +class EventSourceBase; + +template +class Event; + +template +class EventSource; + +enum class Token; + +// Observers +class Observer; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// Traits +/////////////////////////////////////////////////////////////////////////////////////////////////// +template +struct IsSignal { static const bool value = false; }; + +template +struct IsSignal> { static const bool value = true; }; + +template +struct IsSignal> { static const bool value = true; }; + +template +struct IsEvent { static const bool value = false; }; + +template +struct IsEvent> { static const bool value = true; }; + +template +struct IsEvent> { static const bool value = true; }; + +template +struct AsNonInputNode { using type = T; }; + +template +struct AsNonInputNode> { using type = Signal; }; + +template +struct AsNonInputNode> { using type = Event; }; + +/******************************************/ REACT_END /******************************************/ + +#endif // REACT_TYPETRAITS_H_INCLUDED \ No newline at end of file diff --git a/include/react/Algorithm.h b/include/react/Algorithm.h index b6da68af..e2a1f3a9 100644 --- a/include/react/Algorithm.h +++ b/include/react/Algorithm.h @@ -15,32 +15,16 @@ #include #include +#include "react/API.h" #include "react/detail/graph/AlgorithmNodes.h" /*****************************************/ REACT_BEGIN /*****************************************/ -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Forward declarations -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -class Signal; - -template -class VarSignal; - -template -class Events; - -template -class EventSource; - -enum class Token; - /////////////////////////////////////////////////////////////////////////////////////////////////// /// Hold - Hold the most recent event in a signal /////////////////////////////////////////////////////////////////////////////////////////////////// -template -auto Hold(const Events& events, V&& init) -> Signal +template +auto Hold(const Events& events, U&& init) -> Signal { using REACT_IMPL::HoldNode; diff --git a/include/react/Event.h b/include/react/Event.h index 599c2ad6..5af37093 100644 --- a/include/react/Event.h +++ b/include/react/Event.h @@ -10,72 +10,287 @@ #pragma once #include "react/detail/Defs.h" +#include "react/API.h" +#include "react/Group.h" #include #include #include -#include "react/Observer.h" -#include "react/TypeTraits.h" -#include "react/common/Util.h" -#include "react/detail/EventBase.h" +#include "react/detail/graph/EventNodes.h" /*****************************************/ REACT_BEGIN /*****************************************/ /////////////////////////////////////////////////////////////////////////////////////////////////// -/// Forward declarations +/// Events +/////////////////////////////////////////////////////////////////////////////////////////////////// + +template +class EventBase +{ +private: + using NodeType = REACT_IMPL::EventStreamNode; + +public: + EventBase() = default; + + EventBase(const EventBase&) = default; + EventBase& operator=(const EventBase&) = default; + + EventBase(EventBase&&) = default; + EventBase& operator=(EventBase&&) = default; + + ~EventBase() = default; + + // Node ctor + explicit EventBase(std::shared_ptr&& nodePtr) : + nodePtr_( std::move(nodePtr) ) + { } + + auto Tokenize() const -> decltype(auto) + { return REACT::Tokenize(*this); } + + /*template + auto Merge(Us&& ... deps) const -> decltype(auto) + { return REACT::Merge(*this, std::forward(deps) ...); } + + template + auto Filter(F&& pred) const -> decltype(auto) + { return REACT::Filter(std::forward(pred), *this); } + + template + auto Transform(F&& pred) const -> decltype(auto) + { return REACT::Transform(*this, std::forward(f)); }*/ + +protected: + auto NodePtr() -> std::shared_ptr& + { return nodePtr_; } + + auto NodePtr() const -> const std::shared_ptr& + { return nodePtr_; } + + template + auto CreateProcessingNode(FIn&& func, const EventBase& dep) -> decltype(auto) + { + using F = typename std::decay::type; + using ProcessingNodeType = REACT_IMPL::EventProcessingNode; + + return std::make_shared( + REACT_IMPL::PrivateNodeInterface::GraphPtr(dep), + REACT_IMPL::PrivateNodeInterface::NodePtr(dep), + std::forward(func)); + } + +private: + std::shared_ptr nodePtr_; + + friend struct REACT_IMPL::PrivateNodeInterface; +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// EventSource +/////////////////////////////////////////////////////////////////////////////////////////////////// +template +class EventSourceBase : public EventBase +{ +private: + using NodeType = REACT_IMPL::EventSourceNode; + +public: + using EventBase::EventBase; + + EventSourceBase() = default; + + EventSourceBase(const EventSourceBase&) = default; + EventSourceBase& operator=(const EventSourceBase&) = default; + + EventSourceBase(EventSourceBase&& other) = default; + EventSourceBase& operator=(EventSourceBase&& other) = default; + + template + explicit EventSourceBase(const TGroup& group) : + EventSourceBase::EventBase( std::make_shared(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group)) ) + { } + + void Emit(const T& value) + { EmitValue(value); } + + void Emit(T&& value) + { EmitValue(std::move(value)); } + + template ::value>::type> + void Emit() + { EmitValue(Token::value); } + + EventSourceBase& operator<<(const T& value) + { EmitValue(e); return *this; } + + EventSourceBase& operator<<(T&& value) + { EmitValue(std::move(value)); return *this; } + +private: + template + void EmitValue(U&& value) + { + using REACT_IMPL::NodeId; + using REACT_IMPL::IReactiveGraph; + + NodeType* castedPtr = static_cast(this->NodePtr().get()); + + NodeId nodeId = castedPtr->GetNodeId(); + auto& graphPtr = NodePtr()->GraphPtr(); + graphPtr->AddInput(nodeId, [castedPtr, &value] { castedPtr->EmitValue(std::forward(value)); }); + } +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// Event /////////////////////////////////////////////////////////////////////////////////////////////////// template -class EventStream; +class Event : public EventBase +{ +public: + using EventBase::EventBase; + + using ValueType = T; + + Event() = delete; + + Event(const Event&) = delete; + Event& operator=(const Event&) = delete; + + Event(Event&&) = default; + Event& operator=(Event&&) = default; + + template + Event(F&& func, const EventBase& dep) : + Event::EventBase( CreateProcessingNode(std::forward(func), dep) ) + { } +}; template -class EventSource; +class Event : public EventBase +{ +public: + using EventBase::EventBase; + + using ValueType = T; + + Event() = delete; + + Event(const Event&) = default; + Event& operator=(const Event&) = default; + + Event(Event&&) = default; + Event& operator=(Event&&) = default; + + Event(Event&& other) : + Event::EventBase( std::move(other) ) + { } + + Event& operator=(Event&& other) + { Event::EventBase::operator=(std::move(other)); return *this; } + + template + Event(F&& func, const EventBase& dep) : + Event::EventBase( CreateProcessingNode(std::forward(func), dep) ) + { } +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// EventSource +/////////////////////////////////////////////////////////////////////////////////////////////////// +template +class EventSource : public EventSourceBase +{ +public: + using EventSourceBase::EventSourceBase; + + using ValueType = T; + + EventSource() = delete; -enum class Token; + EventSource(const EventSource&) = delete; + EventSource& operator=(const EventSource&) = delete; + + EventSource(EventSource&&) = default; + EventSource& operator=(EventSource&&) = default; +}; template -class Signal; +class EventSource : public EventSourceBase +{ +public: + using EventSourceBase::EventSourceBase; + + using ValueType = T; + + EventSource() = delete; + + EventSource(const EventSource&) = default; + EventSource& operator=(const EventSource&) = default; -using REACT_IMPL::WeightHint; + EventSource(EventSource&&) = default; + EventSource& operator=(EventSource&&) = default; + + EventSource(EventSource&& other) : + EventSource::EventSourceBase( std::move(other) ) + { } + + EventSource& operator=(EventSource&& other) + { EventSource::EventSourceBase::operator=(std::move(other)); return *this; } +}; /////////////////////////////////////////////////////////////////////////////////////////////////// /// Merge /////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename TArg1, - typename ... TArgs, - typename E = TArg1 -> -auto Merge(const Events& arg1, const Events& ... args) -> Events +template +auto Merge(const EventBase& dep1, const EventBase& ... deps) -> decltype(auto) { - using REACT_IMPL::EventOpNode; + using REACT_IMPL::EventMergeNode; + using REACT_IMPL::GetCheckedGraphPtr; + using REACT_IMPL::PrivateNodeInterface; + + static_assert(sizeof...(Us) > 0, "Merge: 2+ arguments are required."); - static_assert(sizeof...(TArgs) > 0, "Merge: 2+ arguments are required."); + // If supplied, use merge type, otherwise default to common type. + using E = typename std::conditional< + std::is_same::value, + typename std::common_type::type, + T>::type; - return Events( - std::make_shared>( - GetNodePtr(arg1), GetNodePtr(args) ...)); + const auto& graphPtr = GetCheckedGraphPtr(dep1, deps ...); + + return Event( + std::make_shared>(graphPtr, PrivateNodeInterface::NodePtr(dep1), PrivateNodeInterface::NodePtr(deps) ...)); } /////////////////////////////////////////////////////////////////////////////////////////////////// /// Filter /////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename E, - typename FIn, - typename F = typename std::decay::type -> -auto Filter(const Events& src, FIn&& filter) -> Events +template +auto Filter(F&& pred, const EventBase& dep) -> Event { - using REACT_IMPL::EventOpNode; + auto filterFunc = [capturedPred = std::forward(pred)] (EventRange inRange, EventSink out) + { std::copy_if(inRange.begin(), inRange.end(), out, capturedPred); }; - return Events( - std::make_shared>( - std::forward(filter), GetNodePtr(src))); + return Event(std::move(filterFunc), dep); } +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// Transform +/////////////////////////////////////////////////////////////////////////////////////////////////// +template +auto Transform(F&& op, const EventBase& dep) -> Event +{ + auto transformFunc = [capturedPred = std::forward(op)] (EventRange inRange, EventSink out) + { std::transform(inRange.begin(), inRange.end(), out, pred); }; + + return Event(std::move(transformFunc), dep); +} + +#if 0 + /////////////////////////////////////////////////////////////////////////////////////////////////// /// Filter - Synced /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -115,24 +330,7 @@ auto Filter(const Events& source, const SignalPack& depPack, F depPack.Data); } -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Transform -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename TIn, - typename FIn, - typename F = typename std::decay::type, - typename TOut = typename std::result_of::type -> -auto Transform(const Events& src, FIn&& func) -> Events -{ - using REACT_IMPL::EventOpNode; - return Events( - std::make_shared>( - std::forward(func), GetNodePtr(src))); -} /////////////////////////////////////////////////////////////////////////////////////////////////// /// Transform - Synced @@ -174,28 +372,6 @@ auto Transform(const Events& source, FIn&& func, const Signal& depPack.Data); } -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Process -/////////////////////////////////////////////////////////////////////////////////////////////////// -using REACT_IMPL::EventRange; -using REACT_IMPL::EventEmitter; - -template -< - typename TOut, - typename TIn, - typename FIn, - typename F = typename std::decay::type -> -auto Process(const Events& src, FIn&& func) -> Events -{ - using REACT_IMPL::EventProcessingNode; - - return Events( - std::make_shared>( - GetNodePtr(src), std::forward(func))); -} - /////////////////////////////////////////////////////////////////////////////////////////////////// /// Process - Synced /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -279,155 +455,14 @@ auto Tokenize(T&& source) -> decltype(auto) return Transform(source, Tokenizer{ }); } -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Events -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -class Events : public REACT_IMPL::EventStreamBase -{ -private: - using NodeType = REACT_IMPL::EventStreamNode; - using NodePtrType = std::shared_ptr; - -public: - using ValueType = T; - - // Default ctor - Events() = default; - - // Copy ctor - Events(const Events&) = default; - - // Move ctor - Events(Events&& other) = default; - - // Node ctor - explicit Events(NodePtrT&& nodePtr) = default; - - // Copy assignment - Events& operator=(const Events&) = default; - - // Move assignment - Events& operator=(Events&& other) = default; - - bool Equals(const Events& other) const - { - return Events::EventStreamBase::Equals(other); - } - - bool IsValid() const - { - return Events::EventStreamBase::IsValid(); - } - - void SetWeightHint(WeightHint weight) - { - Events::EventStreamBase::SetWeightHint(weight); - } - - auto Tokenize() const -> decltype(auto) - { - return REACT::Tokenize(*this); - } - - template - auto Merge(TArgs&& ... args) const -> decltype(auto) - { - return REACT::Merge(*this, std::forward(args) ...); - } - - template - auto Filter(F&& f) const -> decltype(auto) - { - return REACT::Filter(*this, std::forward(f)); - } - - template - auto Transform(F&& f) const -> decltype(auto) - { - return REACT::Transform(*this, std::forward(f)); - } - - template - static auto Create() -> EventSource - { - using REACT_IMPL::EventSourceNode; - - return EventSource(std::make_shared>()); - } -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// EventSource -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -class EventSource : public Events -{ -private: - using NodeType = REACT_IMPL::EventSourceNode; - using NodePtrType = std::shared_ptr; - -public: - // Default ctor - EventSource() = default; - - // Copy ctor - EventSource(const EventSource&) = default; - - // Move ctor - EventSource(EventSource&& other) = default; - - // Node ctor - explicit EventSource(NodePtrT&& nodePtr) : - EventSource::Events( std::move(nodePtr) ) - {} - - // Copy assignemnt - EventSource& operator=(const EventSource&) = default; - - // Move assignment - EventSource& operator=(EventSource&& other) = default; - - // Explicit emit - void Emit(const T& e) const { EventSource::EventStreamBase::emit(e); } - void Emit(T&& e) const { EventSource::EventStreamBase::emit(std::move(e)); } - - void Emit() const - { - static_assert(std::is_same::value, "Can't emit on non token stream."); - EventSource::EventStreamBase::emit(Token::value); - } - - // Function object style - void operator()(const E& e) const { EventSource::EventStreamBase::emit(e); } - void operator()(E&& e) const { EventSource::EventStreamBase::emit(std::move(e)); } - - void operator()() const - { - static_assert(std::is_same::value, "Can't emit on non token stream."); - EventSource::EventStreamBase::emit(Token::value); - } - - // Stream style - const EventSource& operator<<(const T& e) const - { - EventSource::EventStreamBase::emit(e); - return *this; - } - - const EventSource& operator<<(T&& e) const - { - EventSource::EventStreamBase::emit(std::move(e)); - return *this; - } -}; +#endif /******************************************/ REACT_END /******************************************/ /***************************************/ REACT_IMPL_BEGIN /**************************************/ template -bool Equals(const Events& lhs, const Events& rhs) +bool Equals(const EventBase& lhs, const EventBase& rhs) { return lhs.Equals(rhs); } diff --git a/include/react/Domain.h b/include/react/Group.h similarity index 52% rename from include/react/Domain.h rename to include/react/Group.h index b1fae362..cf58e72a 100644 --- a/include/react/Domain.h +++ b/include/react/Group.h @@ -14,62 +14,25 @@ #include #include -#include "react/detail/DomainBase.h" -#include "react/detail/ReactiveInput.h" +#include "react/API.h" +#include "react/Signal.h" +//#include "react/Event.h" -#include "react/detail/graph/ContinuationNodes.h" +#include "react/detail/IReactiveGraph.h" +#include "react/detail/graph/PropagationST.h" -#ifdef REACT_ENABLE_LOGGING - #include "react/logging/EventLog.h" - #include "react/logging/EventRecords.h" -#endif //REACT_ENABLE_LOGGING +/***************************************/ REACT_IMPL_BEGIN /**************************************/ -/*****************************************/ REACT_BEGIN /*****************************************/ - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Forward declarations -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -class Signal; - -template -class VarSignal; - -template -class Events; - -template -class EventSource; - -enum class Token; +struct PrivateReactiveGroupInterface; +struct PrivateConcurrentReactiveGroupInterface; -class Observer; +/****************************************/ REACT_IMPL_END /***************************************/ -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Common types & constants -/////////////////////////////////////////////////////////////////////////////////////////////////// -using REACT_IMPL::TransactionFlagsT; - -// ETransactionFlags -using REACT_IMPL::ETransactionFlags; -using REACT_IMPL::allow_merging; - -#ifdef REACT_ENABLE_LOGGING - using REACT_IMPL::EventLog; -#endif //REACT_ENABLE_LOGGING +/*****************************************/ REACT_BEGIN /*****************************************/ -// Domain modes -using REACT_IMPL::EDomainMode; -using REACT_IMPL::sequential; -using REACT_IMPL::sequential_concurrent; -using REACT_IMPL::parallel; -using REACT_IMPL::parallel_concurrent; -// Expose enum type so aliases for engines can be declared, but don't -// expose the actual enum values as they are reserved for internal use. -using REACT_IMPL::EPropagationMode; -using REACT_IMPL::WeightHint; +#if 0 /////////////////////////////////////////////////////////////////////////////////////////////////// /// TransactionStatus @@ -134,7 +97,7 @@ void DoTransaction(F&& func) } template -void DoTransaction(TransactionFlagsT flags, F&& func) +void DoTransaction(TransactionFlags flags, F&& func) { using REACT_IMPL::DomainSpecificInputManager; DomainSpecificInputManager::Instance().DoTransaction(flags, std::forward(func)); @@ -155,7 +118,7 @@ void AsyncTransaction(F&& func) } template -void AsyncTransaction(TransactionFlagsT flags, F&& func) +void AsyncTransaction(TransactionFlags flags, F&& func) { static_assert(D::is_concurrent, "AsyncTransaction: Domain does not support concurrent input."); @@ -188,45 +151,124 @@ void AsyncTransaction(TransactionFlagsT flags, TransactionStatus& status, F&& fu .AsyncTransaction(flags, status.statePtr_, std::forward(func)); } -/******************************************/ REACT_END /******************************************/ +#endif /////////////////////////////////////////////////////////////////////////////////////////////////// -/// Domain definition macro +/// ReactiveGroupBase /////////////////////////////////////////////////////////////////////////////////////////////////// -#define REACTIVE_DOMAIN(name, ...) \ - struct name : \ - public REACT_IMPL::DomainBase> {}; \ - static REACT_IMPL::DomainInitializer name ## _initializer_; - -/* - A brief reminder why the domain initializer is here: - Each domain has a couple of singletons (debug log, engine, input manager) which are - currently implemented as meyer singletons. From what I understand, these are thread-safe - in C++11, but not all compilers implement that yet. That's why a static initializer has - been added to make sure singleton creation happens before any multi-threaded access. - This implemenation is obviously inconsequential. - */ +class ReactiveGroupBase +{ + using GraphType = REACT_IMPL::SingleThreadedGraph; + +public: + ReactiveGroupBase() : + graphPtr_( std::make_shared() ) + { } + + ReactiveGroupBase(const ReactiveGroupBase&) = default; + ReactiveGroupBase& operator=(const ReactiveGroupBase&) = default; + + ReactiveGroupBase(ReactiveGroupBase&& other) = default; + ReactiveGroupBase& operator=(ReactiveGroupBase&& other) = default; + + ~ReactiveGroupBase() = default; + + template + void DoTransaction(F&& func) + { DoTransaction(TransactionFlags::none, std::forward(func)); } + + template + void DoTransaction(TransactionFlags flags, F&& func) + { graphPtr_->DoTransaction(flags, std::forward(func)); } + +protected: + auto GraphPtr() -> std::shared_ptr& + { return graphPtr_; } + + auto GraphPtr() const -> const std::shared_ptr& + { return graphPtr_; } + +private: + std::shared_ptr graphPtr_; + + friend struct REACT_IMPL::PrivateReactiveGroupInterface; +}; /////////////////////////////////////////////////////////////////////////////////////////////////// -/// Define type aliases for given domain +/// Signal /////////////////////////////////////////////////////////////////////////////////////////////////// -#define USING_REACTIVE_DOMAIN(name) \ - template \ - using SignalT = Signal; \ - \ - template \ - using VarSignalT = VarSignal; \ - \ - template \ - using EventsT = Events; \ - \ - template \ - using EventSourceT = EventSource; \ - \ - using ObserverT = Observer; \ - \ - using ScopedObserverT = ScopedObserver; \ - \ - using ReactorT = Reactor; +template <> +class ReactiveGroup : public ReactiveGroupBase +{ +public: + ReactiveGroup() = default; + + ReactiveGroup(const ReactiveGroup&) = delete; + ReactiveGroup& operator=(const ReactiveGroup&) = delete; + + ReactiveGroup(ReactiveGroup&& other) = default; + ReactiveGroup& operator=(ReactiveGroup&& other) = default; +}; + +template <> +class ReactiveGroup : public ReactiveGroupBase +{ +public: + ReactiveGroup() = default; + + ReactiveGroup(const ReactiveGroup&) = default; + ReactiveGroup& operator=(const ReactiveGroup&) = default; + + ReactiveGroup(ReactiveGroup&& other) = default; + ReactiveGroup& operator=(ReactiveGroup&& other) = default; +}; + +/******************************************/ REACT_END /******************************************/ + +/***************************************/ REACT_IMPL_BEGIN /**************************************/ + +struct PrivateNodeInterface +{ + template + static auto NodePtr(const TBase& base) -> const std::shared_ptr& + { return base.NodePtr(); } + + template + static auto NodePtr(TBase& base) -> std::shared_ptr& + { return base.NodePtr(); } + + template + static auto GraphPtr(const TBase& base) -> const std::shared_ptr& + { return base.NodePtr()->GraphPtr(); } + + template + static auto GraphPtr(TBase& base) -> std::shared_ptr& + { return base.NodePtr()->GraphPtr(); } +}; + +struct PrivateReactiveGroupInterface +{ + static auto GraphPtr(const ReactiveGroupBase& group) -> const std::shared_ptr& + { return group.GraphPtr(); } + + static auto GraphPtr(ReactiveGroupBase& group) -> std::shared_ptr& + { return group.GraphPtr(); } +}; + +template +static auto GetCheckedGraphPtr(const TBase1& dep1, const TBases& ... deps) -> const std::shared_ptr& +{ + const std::shared_ptr& graphPtr1 = PrivateNodeInterface::GraphPtr(dep1); + + auto rawGraphPtrs = { PrivateNodeInterface::GraphPtr(deps).get() ... }; + + bool isSameGraphForAllDeps = std::all_of(rawGraphPtrs.begin(), rawGraphPtrs.end(), [&] (IReactiveGraph* p) { return p == graphPtr1.get(); }); + + REACT_ASSERT(isSameGraphForAllDeps, "All dependencies must belong to the same group."); + + return graphPtr1; +} + +/****************************************/ REACT_IMPL_END /***************************************/ #endif // REACT_DOMAIN_H_INCLUDED \ No newline at end of file diff --git a/include/react/Observer.h b/include/react/Observer.h index 17e72ebf..705d4ee9 100644 --- a/include/react/Observer.h +++ b/include/react/Observer.h @@ -4,6 +4,8 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) +#if 0 + #ifndef REACT_OBSERVER_H_INCLUDED #define REACT_OBSERVER_H_INCLUDED @@ -333,4 +335,6 @@ auto Observe(const Events& subject, /******************************************/ REACT_END /******************************************/ -#endif // REACT_OBSERVER_H_INCLUDED \ No newline at end of file +#endif // REACT_OBSERVER_H_INCLUDED + +#endif \ No newline at end of file diff --git a/include/react/Signal.h b/include/react/Signal.h index 4bf28460..ea60ce3a 100644 --- a/include/react/Signal.h +++ b/include/react/Signal.h @@ -14,192 +14,267 @@ #endif #include "react/detail/Defs.h" +#include "react/API.h" +#include "react/Group.h" #include #include #include #include -#include "react/Observer.h" -#include "react/TypeTraits.h" -#include "react/detail/SignalBase.h" +#include "react/detail/graph/SignalNodes.h" /*****************************************/ REACT_BEGIN /*****************************************/ /////////////////////////////////////////////////////////////////////////////////////////////////// -/// Forward declarations +/// SignalBase /////////////////////////////////////////////////////////////////////////////////////////////////// template -class Signal; +class SignalBase +{ +private: + using NodeType = REACT_IMPL::SignalNode; -template -class VarSignal; +public: + SignalBase() = default; -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Flatten -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -auto Flatten(const Signal>& outer) - -> Signal -{ - return Signal( - std::make_shared, TInnerValue>>( - GetNodePtr(outer), GetNodePtr(outer.Value()))); -} + SignalBase(const SignalBase&) = default; + SignalBase& operator=(const SignalBase&) = default; + + SignalBase(SignalBase&&) = default; + SignalBase& operator=(SignalBase&&) = default; + + ~SignalBase() = default; + + // Internal node ctor + explicit SignalBase(std::shared_ptr&& nodePtr) : + nodePtr_( std::move(nodePtr) ) + { } + + const T& Value() const + { return nodePtr_->Value(); } + +protected: + auto NodePtr() -> std::shared_ptr& + { return nodePtr_; } + + auto NodePtr() const -> const std::shared_ptr& + { return nodePtr_; } + + template + auto CreateFuncNode(FIn&& func, const SignalBase& dep1, const SignalBase& ... deps) -> decltype(auto) + { + using F = typename std::decay::type; + using FuncNodeType = REACT_IMPL::SignalFuncNode; + + return std::make_shared( + REACT_IMPL::GetCheckedGraphPtr(dep1, deps ...), + std::forward(func), + REACT_IMPL::PrivateNodeInterface::NodePtr(dep1), REACT_IMPL::PrivateNodeInterface::NodePtr(deps) ...); + } + +private: + std::shared_ptr nodePtr_; + + friend struct REACT_IMPL::PrivateNodeInterface; +}; /////////////////////////////////////////////////////////////////////////////////////////////////// -/// Signal +/// VarSignalBase /////////////////////////////////////////////////////////////////////////////////////////////////// template -class Signal : public REACT_IMPL::SignalBase +class VarSignalBase : public SignalBase { -private: - using NodeType = REACT_IMPL::SignalNode; - using NodePtrType = std::shared_ptr; - public: - using ValueType = T; + using SignalBase::SignalBase; - // Default ctor - Signal() = default; + VarSignalBase() = default; - // Copy ctor - Signal(const Signal&) = default; + VarSignalBase(const VarSignalBase&) = default; + VarSignalBase& operator=(const VarSignalBase&) = default; - // Move ctor - Signal(Signal&& other) = default; + VarSignalBase(VarSignalBase&&) = default; + VarSignalBase& operator=(VarSignalBase&&) = default; - // Node ctor - explicit Signal(NodePtrType&& nodePtr) : - Signal::SignalBase( std::move(nodePtr) ) - {} + void Set(const T& newValue) + { SetValue(newValue); } - // Copy assignment - Signal& operator=(const Signal&) = default; + void Set(T&& newValue) + { SetValue(std::move(newValue)); } - // Move assignment - Signal& operator=(Signal&& other) = default; + void operator<<=(const T& newValue) + { SetValue(newValue); } - const S& Get() const { return Signal::SignalBase::getValue(); } - const S& operator()() const { return Signal::SignalBase::getValue(); } + void operator<<=(T&& newValue) + { SetValue(std::move(newValue)); } - bool Equals(const Signal& other) const - { - return Signal::SignalBase::Equals(other); - } + template + void Modify(const F& func) + { ModifyValue(func); } - bool IsValid() const +protected: + template + auto CreateVarNode(U&& value, const TGroup& group) -> decltype(auto) { - return Signal::SignalBase::IsValid(); + using VarNodeType = REACT_IMPL::VarSignalNode; + return std::make_shared(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), std::forward(value)); } - void SetWeightHint(WeightHint weight) +private: + template + void SetValue(U&& newValue) { - Signal::SignalBase::SetWeightHint(weight); - } + using REACT_IMPL::NodeId; + using REACT_IMPL::IReactiveGraph; + using VarNodeType = REACT_IMPL::VarSignalNode; - S Flatten() const - { - static_assert(IsSignal::value || IsEvent::value, - "Flatten requires a Signal or Events value type."); - return REACT::Flatten(*this); + VarNodeType* castedPtr = static_cast(this->NodePtr().get()); + + NodeId nodeId = castedPtr->GetNodeId(); + auto& graphPtr = NodePtr()->GraphPtr(); + graphPtr->AddInput(nodeId, [castedPtr, &newValue] { castedPtr->SetValue(std::forward(newValue)); }); } - template - < - typename ... Ts, - typename FIn, - typename F = typename std::decay::type - > - static auto Create(FIn&& func, const Signal& ... args) -> Signal + template + void ModifyValue(const F& func) { - return Signal( - std::make_shared>( - std::forward(func), GetNodePtr(args) ...)); + using REACT_IMPL::NodeId; + using REACT_IMPL::IReactiveGraph; + using VarNodeType = REACT_IMPL::VarSignalNode; + + VarNodeType* castedPtr = static_cast(this->NodePtr().get()); + + NodeId nodeId = castedPtr->GetNodeId(); + auto& graphPtr = castedPtr->GraphPtr(); + graphPtr->AddInput(nodeId, [castedPtr, &func] { castedPtr->ModifyValue(func); }); } }; /////////////////////////////////////////////////////////////////////////////////////////////////// -/// VarSignal +/// Signal /////////////////////////////////////////////////////////////////////////////////////////////////// -template -class VarSignal : public Signal +template +class Signal : public SignalBase { -private: - using NodeT = REACT_IMPL::VarNode; - using NodePtrT = std::shared_ptr; +public: + using SignalBase::SignalBase; + + using ValueType = T; + + Signal() = delete; + + Signal(const Signal&) = delete; + Signal& operator=(const Signal&) = delete; + + Signal(Signal&&) = default; + Signal& operator=(Signal&&) = default; + + template + Signal(F&& func, const SignalBase& ... deps) : + SignalBase( CreateFuncNode(std::forward(func), deps ...) ) + { } +}; + +template +class Signal : public SignalBase +{ +public: + using SignalBase::SignalBase; + + using ValueType = T; + + Signal() = delete; + + Signal(const Signal&) = default; + Signal& operator=(const Signal&) = default; + + Signal(Signal&&) = default; + Signal& operator=(Signal&&) = default; + + Signal(Signal&& other) : + Signal::SignalBase( std::move(other) ) + { } + + Signal& operator=(Signal&& other) + { Signal::SignalBase::operator=(std::move(other)); return *this; } + + template + Signal(F&& func, const SignalBase& ... deps) : + Signal::SignalBase( CreateFuncNode(std::forward(func), deps ...) ) + { } +}; +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// Signal +/////////////////////////////////////////////////////////////////////////////////////////////////// +template +class VarSignal : public VarSignalBase +{ public: - // Default ctor - VarSignal() = default; + using VarSignalBase::VarSignalBase; - // Copy ctor - VarSignal(const VarSignal&) = default; + using ValueType = T; - // Move ctor - VarSignal(VarSignal&& other) : - VarSignal::Signal( std::move(other) ) - {} + VarSignal() = delete; - // Node ctor - explicit VarSignal(NodePtrT&& nodePtr) : - VarSignal::Signal( std::move(nodePtr) ) - {} + VarSignal(const VarSignal&) = delete; + VarSignal& operator=(const VarSignal&) = delete; - // Copy assignment - VarSignal& operator=(const VarSignal&) = default; + VarSignal(VarSignal&&) = default; + VarSignal& operator=(VarSignal&&) = default; - // Move assignment - VarSignal& operator=(VarSignal&& other) - { - VarSignal::SignalBase::operator=( std::move(other) ); - return *this; - } + template + VarSignal(U&& value, const TGroup& group) : + VarSignal::VarSignalBase( CreateVarNode(std::forward(value), group) ) + { } +}; - void Set(const S& newValue) const - { - VarSignal::SignalBase::setValue(newValue); - } +template +class VarSignal : public VarSignalBase +{ +public: + using VarSignalBase::VarSignalBase; - void Set(S&& newValue) const - { - VarSignal::SignalBase::setValue(std::move(newValue)); - } + using ValueType = T; - const VarSignal& operator<<=(const S& newValue) const - { - VarSignal::SignalBase::setValue(newValue); - return *this; - } + VarSignal() = delete; - const VarSignal& operator<<=(S&& newValue) const - { - VarSignal::SignalBase::setValue(std::move(newValue)); - return *this; - } + VarSignal(const VarSignal&) = default; + VarSignal& operator=(const VarSignal&) = default; - template - void Modify(const F& func) const - { - VarSignal::SignalBase::modifyValue(func); - } + VarSignal(VarSignal&&) = default; + VarSignal& operator=(VarSignal&&) = default; - /// Create - template - static auto Create(V&& value) -> VarSignal - { - return VarSignal( - std::make_shared>( - std::forward(value))); - } + VarSignal(VarSignal&& other) : + VarSignal::VarSignalBase( std::move(other) ) + { } + + VarSignal& operator=(VarSignal&& other) + { VarSignal::SignalBase::operator=(std::move(other)); return *this; } + + template + VarSignal(U&& value, const TGroup& group) : + VarSignal::VarSignalBase( CreateVarNode(std::forward(value), group) ) + { } }; +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// Flatten +/////////////////////////////////////////////////////////////////////////////////////////////////// +/*template +auto Flatten(const SignalBase>& outer) -> Signal +{ + return Signal( + std::make_shared, TInner>>( + GetNodePtr(outer), GetNodePtr(outer.Value()))); +}*/ + /******************************************/ REACT_END /******************************************/ /***************************************/ REACT_IMPL_BEGIN /**************************************/ template -bool Equals(const Signal& lhs, const Signal& rhs) +bool Equals(const SignalBase& lhs, const SignalBase& rhs) { return lhs.Equals(rhs); } diff --git a/include/react/TypeTraits.h b/include/react/TypeTraits.h deleted file mode 100644 index 97c12654..00000000 --- a/include/react/TypeTraits.h +++ /dev/null @@ -1,92 +0,0 @@ - -// Copyright Sebastian Jeckel 2016. -// 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) - -#ifndef REACT_TYPETRAITS_H_INCLUDED -#define REACT_TYPETRAITS_H_INCLUDED - -#pragma once - -#include "react/detail/Defs.h" - -/*****************************************/ REACT_BEGIN /*****************************************/ - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Forward declarations -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -class Signal; - -template -class VarSignal; - -template -class Events; - -template -class EventSource; - -class Observer; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// IsSignal -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -struct IsSignal { static const bool value = false; }; - -template -struct IsSignal> { static const bool value = true; }; - -template -struct IsSignal> { static const bool value = true; }; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// IsEvent -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -struct IsEvent { static const bool value = false; }; - -template -struct IsEvent> { static const bool value = true; }; - -template -struct IsEvent> { static const bool value = true; }; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// IsReactive -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -struct IsReactive { static const bool value = false; }; - -template -struct IsReactive> { static const bool value = true; }; - -template -struct IsReactive> { static const bool value = true; }; - -template -struct IsReactive> { static const bool value = true; }; - -template -struct IsReactive> { static const bool value = true; }; - -template <> -struct IsReactive { static const bool value = true; }; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// DecayInput -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -struct DecayInput { using Type = T; }; - -template -struct DecayInput> { using Type = Signal; }; - -template -struct DecayInput> { using Type = Events; }; - -/******************************************/ REACT_END /******************************************/ - -#endif // REACT_TYPETRAITS_H_INCLUDED \ No newline at end of file diff --git a/include/react/common/Containers.h b/include/react/common/Containers.h index 1839bd46..a03257db 100644 --- a/include/react/common/Containers.h +++ b/include/react/common/Containers.h @@ -13,6 +13,7 @@ #include #include +#include #include #include @@ -40,6 +41,153 @@ class EnumFlags FlagsT flags_ = 0; }; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// IndexMap +/////////////////////////////////////////////////////////////////////////////////////////////////// +template +class IndexMap +{ + static const size_t initial_capacity = 8; + static const size_t grow_factor = 2; + +public: + using ValueType = T; + + IndexMap() = default; + + IndexMap(const IndexMap&) = default; + IndexMap& operator=(const IndexMap&) = default; + + IndexMap(IndexMap&&) = default; + IndexMap& operator=(IndexMap&&) = default; + + T& operator[](size_t index) + { return data_[index]; } + + const T& operator[](size_t index) const + { return data_[index]; } + + size_t Insert(T value) + { + if (IsAtFullCapacity()) + { + Grow(); + return InsertAtBack(std::move(value)); + } + else if (HasFreeIndices()) + { + return InsertAtFreeIndex(std::move(value)); + } + else + { + return InsertAtBack(std::move(value)); + } + } + + void Remove(size_t index) + { + for (size_t index : freeIndices_) + data_[index].~T(); + --size_; + freeIndices_.push_back(index); + } + + void Clear() + { + // Sort free indexes so we can remove check for them in linear time + std::sort(freeIndices_.begin(), freeIndices_.end()); + + const size_t totalSize = size_ + freeIndices_.size(); + size_t i = 0; + + // Skip over free indices + for (auto freeIndex : freeIndices_) + { + for (; i < totalSize; ++i) + { + if (i == freeIndex) + break; + else + data_[i].~T(); + } + } + + // Rest + for (; i < totalSize; ++i) + data_[i].~T(); + + size_ = 0; + freeIndices_.clear(); + } + + void Reset() + { + Clear(); + + capacity_ = 0; + delete[] data_; + + freeIndices_.shrink_to_fit(); + } + + ~IndexMap() + { Reset(); } + +private: + bool IsAtFullCapacity() const + { return capacity_ == size_; } + + bool HasFreeIndices() const + { return !freeIndices_.empty(); } + + size_t CalcNextCapacity() const + { return capacity_ == 0? initial_capacity : capacity_ * grow_factor; } + + void Grow() + { + // Allocate new storage + size_t newCapacity = CalcNextCapacity(); + T* newData = new T[newCapacity]; + + // Move data to new storage + for (size_t i = 0; i < size_; ++i) + { + new (&newData[i]) T(std::move(data_[i])); + data_[i].~T(); + } + + delete[] data_; + + // Use new storage + data_ = newData; + capacity_ = newCapacity; + } + + size_t InsertAtBack(T&& value) + { + new (&data_[size_]) T(std::move(value)); + return size_++; + } + + size_t InsertAtFreeIndex(T&& value) + { + size_t nextFreeIndex = freeIndices_.back(); + freeIndices_.pop_back(); + + new (&data_[nextFreeIndex]) T(std::move(value)); + ++size_; + + return nextFreeIndex; + } + + T* data_ = nullptr; + size_t size_ = 0; + size_t capacity_ = 0; + + std::vector freeIndices_; +}; + /////////////////////////////////////////////////////////////////////////////////////////////////// /// NodeVector /////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/include/react/common/TopoQueue.h b/include/react/common/TopoQueue.h index b86885ff..091d116f 100644 --- a/include/react/common/TopoQueue.h +++ b/include/react/common/TopoQueue.h @@ -25,7 +25,16 @@ /////////////////////////////////////////////////////////////////////////////////////////////////// /// TopoQueue - Sequential /////////////////////////////////////////////////////////////////////////////////////////////////// -template + +template +int GetNodeLevel(const T& node) + { return node.level; } + +template +int GetNodeLevel(const T* node) + { return node->level; } + +template class TopoQueue { private: @@ -39,14 +48,9 @@ class TopoQueue TopoQueue() = default; TopoQueue(const TopoQueue&) = default; - template - TopoQueue(FIn&& levelFunc) : - levelFunc_( std::forward(levelFunc) ) - {} - void Push(const T& value) { - queueData_.emplace_back(value, levelFunc_(value)); + queueData_.emplace_back(value, GetNodeLevel(value)); } bool FetchNext() @@ -64,7 +68,7 @@ class TopoQueue auto p = std::partition( queueData_.begin(), queueData_.end(), - LevelCompFunctor{ minLevel_ }); + [minLevel_] (const Entry& e) { return minLevel_ != e.level; }); // Reserve once to avoid multiple re-allocations nextData_.reserve(std::distance(p, queueData_.end())); diff --git a/include/react/common/Util.h b/include/react/common/Util.h index 19fe74f4..741cd61d 100644 --- a/include/react/common/Util.h +++ b/include/react/common/Util.h @@ -17,6 +17,12 @@ /***************************************/ REACT_IMPL_BEGIN /**************************************/ +template +struct MakeVoid { using type = void;}; + +template +using VoidType = typename MakeVoid::type; + /////////////////////////////////////////////////////////////////////////////////////////////////// /// Unpack tuple - see /// http://stackoverflow.com/questions/687490/how-do-i-expand-a-tuple-into-variadic-template-functions-arguments @@ -25,8 +31,7 @@ template struct Apply { template - static inline auto apply(F && f, T && t, A &&... a) - -> decltype(Apply::apply(std::forward(f), std::forward(t), std::get(std::forward(t)), std::forward(a)...)) + static auto apply(F&& f, T&& t, A&&... a) -> decltype(auto) { return Apply::apply(std::forward(f), std::forward(t), std::get(std::forward(t)), std::forward(a)...); } @@ -36,26 +41,22 @@ template<> struct Apply<0> { template - static inline auto apply(F && f, T &&, A &&... a) - -> decltype(std::forward(f)(std::forward(a)...)) + static auto apply(F&& f, T&&, A&&... a) -> decltype(auto) { return std::forward(f)(std::forward(a)...); } }; template -inline auto apply(F && f, T && t) - -> decltype(Apply::type>::value>::apply(std::forward(f), std::forward(t))) +inline auto apply(F&& f, T&& t) -> decltype(auto) { - return Apply::type>::value> - ::apply(std::forward(f), std::forward(t)); + return Apply::type>::value>::apply(std::forward(f), std::forward(t)); } template struct ApplyMemberFn { template - static inline auto apply(O obj, F f, T && t, A &&... a) - -> decltype(ApplyMemberFn::apply(obj, f, std::forward(t), std::get(std::forward(t)), std::forward(a)...)) + static inline auto apply(O obj, F f, T && t, A &&... a) -> decltype(auto) { return ApplyMemberFn::apply(obj, f, std::forward(t), std::get(std::forward(t)), std::forward(a)...); } @@ -194,12 +195,7 @@ struct AddDefaultReturnValueWrapper /////////////////////////////////////////////////////////////////////////////////////////////////// /// IsCallableWith /////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename F, - typename TRet, - typename ... TArgs -> +template class IsCallableWith { private: @@ -209,9 +205,7 @@ class IsCallableWith template < typename U, - class = decltype( - static_cast( - (std::declval())(std::declval() ...))) + typename = decltype(static_cast((std::declval())(std::declval() ...))) > static YesT& check(void*); @@ -219,7 +213,7 @@ class IsCallableWith static NoT& check(...); public: - enum { value = sizeof(check(nullptr)) == sizeof(YesT) }; + static const bool value = sizeof(check(nullptr)) == sizeof(YesT); }; /****************************************/ REACT_IMPL_END /***************************************/ @@ -228,4 +222,22 @@ class IsCallableWith // Use comma operator to replace potential void return value with 0 #define REACT_EXPAND_PACK(...) REACT_IMPL::pass((__VA_ARGS__ , 0) ...) +#define REACT_DEFINE_BITMASK_OPERATORS(t) \ + inline t operator|(t lhs, t rhs) \ + { return static_cast(static_cast::type>(lhs) | static_cast::type>(rhs)); } \ + inline t operator&(t lhs, t rhs) \ + { return static_cast(static_cast::type>(lhs) & static_cast::type>(rhs)); } \ + inline t operator^(t lhs, t rhs) \ + { return static_cast(static_cast::type>(lhs) ^ static_cast::type>(rhs)); } \ + inline t operator~(t rhs) \ + { return static_cast(~static_cast::type>(rhs)); } \ + inline t& operator|=(t& lhs, t rhs) \ + { lhs = static_cast(static_cast::type>(lhs) | static_cast::type>(rhs)); return lhs; } \ + inline t& operator&=(t& lhs, t rhs) \ + { lhs = static_cast(static_cast::type>(lhs) & static_cast::type>(rhs)); return lhs; } \ + inline t& operator^=(t& lhs, t rhs) \ + { lhs = static_cast(static_cast::type>(lhs) ^ static_cast::type>(rhs)); return lhs; } + +// Bitmask helper + #endif // REACT_COMMON_UTIL_H_INCLUDED \ No newline at end of file diff --git a/include/react/detail/Defs.h b/include/react/detail/Defs.h index 5dd2f91f..24f4cd97 100644 --- a/include/react/detail/Defs.h +++ b/include/react/detail/Defs.h @@ -21,23 +21,10 @@ #define REACT_IMPL_END REACT_END } #define REACT_IMPL REACT ::impl -#ifdef _DEBUG -#define REACT_MESSAGE(...) printf(__VA_ARGS__) -#else -#define REACT_MESSAGE -#endif - // Assert with message #define REACT_ASSERT(condition, ...) for (; !(condition); assert(condition)) printf(__VA_ARGS__) #define REACT_ERROR(...) REACT_ASSERT(false, __VA_ARGS__) -// Logging -#ifdef REACT_ENABLE_LOGGING - #define REACT_LOG(...) __VA_ARGS__ -#else - #define REACT_LOG(...) -#endif - // Thread local storage #if _WIN32 || _WIN64 // MSVC diff --git a/include/react/detail/DomainBase.h b/include/react/detail/DomainBase.h deleted file mode 100644 index 7327874b..00000000 --- a/include/react/detail/DomainBase.h +++ /dev/null @@ -1,265 +0,0 @@ - -// Copyright Sebastian Jeckel 2016. -// 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) - -#ifndef REACT_DETAIL_DOMAINBASE_H_INCLUDED -#define REACT_DETAIL_DOMAINBASE_H_INCLUDED - -#pragma once - -#include -#include - -#include "react/detail/Defs.h" - -#include "react/detail/ReactiveBase.h" -#include "react/detail/IReactiveEngine.h" -#include "react/detail/graph/ContinuationNodes.h" - -// Include all engines for convenience -#include "react/engine/PulsecountEngine.h" -#include "react/engine/SubtreeEngine.h" -#include "react/engine/ToposortEngine.h" - -/*****************************************/ REACT_BEGIN /*****************************************/ - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Forward declarations -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -class Signal; - -template -class VarSignal; - -template -class Events; - -template -class EventSource; - -enum class Token; - -template -class Observer; - -template -class ScopedObserver; - -template -class Reactor; - -/******************************************/ REACT_END /******************************************/ - -/***************************************/ REACT_IMPL_BEGIN /**************************************/ - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Common types & constants -/////////////////////////////////////////////////////////////////////////////////////////////////// - -// Domain modes -enum EDomainMode -{ - sequential, - sequential_concurrent, - parallel, - parallel_concurrent -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// DomainBase -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -class DomainBase -{ -public: - using TurnT = typename TPolicy::Engine::TurnT; - - DomainBase() = delete; - - using Policy = TPolicy; - using Engine = REACT_IMPL::EngineInterface; - - /////////////////////////////////////////////////////////////////////////////////////////////// - /// Domain traits - /////////////////////////////////////////////////////////////////////////////////////////////// - static const bool uses_node_update_timer = - REACT_IMPL::NodeUpdateTimerEnabled::value; - - static const bool is_concurrent = - Policy::input_mode == REACT_IMPL::concurrent_input; - - static const bool is_parallel = - Policy::propagation_mode == REACT_IMPL::parallel_propagation; - - /////////////////////////////////////////////////////////////////////////////////////////////// - /// Aliases for reactives of this domain - /////////////////////////////////////////////////////////////////////////////////////////////// - template - using SignalT = Signal; - - template - using VarSignalT = VarSignal; - - template - using EventsT = Events; - - template - using EventSourceT = EventSource; - - using ObserverT = Observer; - - using ScopedObserverT = ScopedObserver; - - using ReactorT = Reactor; - -#ifdef REACT_ENABLE_LOGGING - /////////////////////////////////////////////////////////////////////////////////////////////// - /// Log - /////////////////////////////////////////////////////////////////////////////////////////////// - static EventLog& Log() - { - static EventLog instance; - return instance; - } -#endif //REACT_ENABLE_LOGGING -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// ContinuationBase -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename D, - typename D2 -> -class ContinuationBase : public MovableReactive> -{ -public: - ContinuationBase() = default; - - template - ContinuationBase(T&& t) : - ContinuationBase::MovableReactive( std::forward(t) ) - {} -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// ModeSelector - Translate domain mode to individual propagation and input modes -/////////////////////////////////////////////////////////////////////////////////////////////////// - -template -struct ModeSelector; - -template <> -struct ModeSelector -{ - static const EInputMode input = consecutive_input; - static const EPropagationMode propagation = sequential_propagation; -}; - -template <> -struct ModeSelector -{ - static const EInputMode input = concurrent_input; - static const EPropagationMode propagation = sequential_propagation; -}; - -template <> -struct ModeSelector -{ - static const EInputMode input = consecutive_input; - static const EPropagationMode propagation = parallel_propagation; -}; - -template <> -struct ModeSelector -{ - static const EInputMode input = concurrent_input; - static const EPropagationMode propagation = parallel_propagation; -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// GetDefaultEngine - Get default engine type for given propagation mode -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -struct GetDefaultEngine; - -template <> -struct GetDefaultEngine -{ - using Type = ToposortEngine; -}; - -template <> -struct GetDefaultEngine -{ - using Type = SubtreeEngine; -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// EngineTypeBuilder - Instantiate the given template engine type with mode. -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -struct DefaultEnginePlaceholder; - -// Concrete engine template type -template -< - EPropagationMode mode, - template class TTEngine -> -struct EngineTypeBuilder -{ - using Type = TTEngine; -}; - -// Placeholder engine type - use default engine for given mode -template -< - EPropagationMode mode -> -struct EngineTypeBuilder -{ - using Type = typename GetDefaultEngine::Type; -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// DomainPolicy -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - EDomainMode mode, - template class TTEngine = DefaultEnginePlaceholder -> -struct DomainPolicy -{ - static const EInputMode input_mode = ModeSelector::input; - static const EPropagationMode propagation_mode = ModeSelector::propagation; - - using Engine = typename EngineTypeBuilder::Type; -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Ensure singletons are created immediately after domain declaration (TODO hax) -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -class DomainInitializer -{ -public: - DomainInitializer() - { -#ifdef REACT_ENABLE_LOGGING - D::Log(); -#endif //REACT_ENABLE_LOGGING - - D::Engine::Instance(); - DomainSpecificInputManager::Instance(); - } -}; - -/****************************************/ REACT_IMPL_END /***************************************/ - -#endif // REACT_DETAIL_DOMAINBASE_H_INCLUDED \ No newline at end of file diff --git a/include/react/detail/EventBase.h b/include/react/detail/EventBase.h deleted file mode 100644 index bf518860..00000000 --- a/include/react/detail/EventBase.h +++ /dev/null @@ -1,49 +0,0 @@ - -// Copyright Sebastian Jeckel 2016. -// 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) - -#ifndef REACT_DETAIL_EVENTBASE_H_INCLUDED -#define REACT_DETAIL_EVENTBASE_H_INCLUDED - -#pragma once - -#include "react/detail/Defs.h" - -#include - -#include "react/detail/ReactiveBase.h" -#include "react/detail/ReactiveInput.h" -#include "react/detail/graph/EventNodes.h" - -/***************************************/ REACT_IMPL_BEGIN /**************************************/ - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// EventStreamBase -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -class EventStreamBase : public ReactiveBase> -{ -public: - EventStreamBase() = default; - EventStreamBase(const EventStreamBase&) = default; - - template - EventStreamBase(T&& t) : - EventStreamBase::CopyableReactive( std::forward(t) ) - {} - -protected: - template - void emit(T&& e) const - { - DomainSpecificInputManager::Instance().AddInput( - *reinterpret_cast*>(this->ptr_.get()), - std::forward(e)); - } -}; - -/****************************************/ REACT_IMPL_END /***************************************/ - -#endif // REACT_DETAIL_EVENTBASE_H_INCLUDED \ No newline at end of file diff --git a/include/react/detail/IReactiveGraph.h b/include/react/detail/IReactiveGraph.h new file mode 100644 index 00000000..ddb29689 --- /dev/null +++ b/include/react/detail/IReactiveGraph.h @@ -0,0 +1,100 @@ + +// Copyright Sebastian Jeckel 2016. +// 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) + +#ifndef REACT_DETAIL_IREACTIVEENGINE_H_INCLUDED +#define REACT_DETAIL_IREACTIVEENGINE_H_INCLUDED + +#pragma once + +#include "react/detail/Defs.h" + +#include +#include +#include + +#include "react/API.h" +#include "react/common/Types.h" +#include "react/common/Util.h" + +/***************************************/ REACT_IMPL_BEGIN /**************************************/ + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// Definitions +/////////////////////////////////////////////////////////////////////////////////////////////////// +using NodeId = size_t; +using TurnId = size_t; + +static NodeId invalid_node_id = (std::numeric_limits::max)(); +static TurnId invalid_turn_id = (std::numeric_limits::max)(); + +enum class UpdateResult +{ + unchanged, + changed, + shifted +}; + +struct IReactiveGraph; +struct IReactiveNode; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// IReactiveGraph +/////////////////////////////////////////////////////////////////////////////////////////////////// +struct IReactiveGraph +{ + virtual ~IReactiveGraph() = default; + + virtual NodeId RegisterNode(IReactiveNode* nodePtr) = 0; + virtual void UnregisterNode(NodeId node) = 0; + + virtual void OnNodeAttach(NodeId nodeId, NodeId parentId) = 0; + virtual void OnNodeDetach(NodeId nodeId, NodeId parentId) = 0; + + virtual void OnDynamicNodeAttach(NodeId nodeId, NodeId parentId, TurnId turn) = 0; + virtual void OnDynamicNodeDetach(NodeId nodeId, NodeId parentId, TurnId turn) = 0; + + virtual void AddInput(NodeId nodeId, std::function inputCallback) = 0; +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// IReactiveNode +/////////////////////////////////////////////////////////////////////////////////////////////////// +struct IReactiveNode +{ + virtual ~IReactiveNode() = default; + + /// Returns unique type identifier + virtual const char* GetNodeType() const = 0; + + // Note: Could get rid of this ugly ptr by adding a template parameter to the interface + // But that would mean all engine nodes need that template parameter too - so rather cast + virtual UpdateResult Update(TurnId turnId) = 0; + + /// Input nodes can be manipulated externally. + virtual bool IsInputNode() const = 0; + + /// Output nodes can't have any successors. + virtual bool IsOutputNode() const = 0; + + /// Dynamic nodes may change in topology as a result of tick. + virtual bool IsDynamicNode() const = 0; + + // Number of predecessors. + virtual int GetDependencyCount() const = 0; +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// EPropagationMode +/////////////////////////////////////////////////////////////////////////////////////////////////// +enum EPropagationMode +{ + sequential_propagation, + parallel_propagation +}; + +/****************************************/ REACT_IMPL_END /***************************************/ + +#endif // REACT_DETAIL_IREACTIVEENGINE_H_INCLUDED \ No newline at end of file diff --git a/include/react/detail/IReactiveGroup.h b/include/react/detail/IReactiveGroup.h deleted file mode 100644 index b86a389c..00000000 --- a/include/react/detail/IReactiveGroup.h +++ /dev/null @@ -1,64 +0,0 @@ - -// Copyright Sebastian Jeckel 2016. -// 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) - -#ifndef REACT_DETAIL_IREACTIVEENGINE_H_INCLUDED -#define REACT_DETAIL_IREACTIVEENGINE_H_INCLUDED - -#pragma once - -#include -#include - -#include "react/detail/Defs.h" -#include "react/common/Types.h" -#include "react/logging/EventRecords.h" - -/***************************************/ REACT_IMPL_BEGIN /**************************************/ - -using NodeId = uint; -using TurnId = uint; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// IReactiveEngine -/////////////////////////////////////////////////////////////////////////////////////////////////// -struct IReactiveGroup -{ - virtual ~IReactiveGroup() = 0; - - virtual void OnTurnAdmissionStart(TurnId turn) = 0; - virtual void OnTurnAdmissionEnd(TurnId turn) = 0; - - virtual void OnInputChange(NodeId node, TurnId turn) = 0; - - virtual void Propagate(TurnId turn) = 0; - - virtual NodeId OnNodeCreate() = 0; - virtual void OnNodeDestroy(NodeId node) = 0; - - virtual void OnNodeAttach(NodeId node, NodeId parent) = 0; - virtual void OnNodeDetach(NodeId node, NodeId parent) = 0; - - virtual void OnDynamicNodeAttach(NodeId node, NodeId parent, TurnId turn) = 0; - virtual void OnDynamicNodeDetach(NodeId node, NodeId parent, TurnId turn) = 0; -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Engine traits -/////////////////////////////////////////////////////////////////////////////////////////////////// -template struct NodeUpdateTimerEnabled : std::false_type {}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// EPropagationMode -/////////////////////////////////////////////////////////////////////////////////////////////////// -enum EPropagationMode -{ - sequential_propagation, - parallel_propagation -}; - -/****************************************/ REACT_IMPL_END /***************************************/ - -#endif // REACT_DETAIL_IREACTIVEENGINE_H_INCLUDED \ No newline at end of file diff --git a/include/react/detail/IReactiveNode.h b/include/react/detail/IReactiveNode.h deleted file mode 100644 index 68fe08be..00000000 --- a/include/react/detail/IReactiveNode.h +++ /dev/null @@ -1,67 +0,0 @@ - -// Copyright Sebastian Jeckel 2016. -// 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) - -#ifndef REACT_DETAIL_IREACTIVENODE_H_INCLUDED -#define REACT_DETAIL_IREACTIVENODE_H_INCLUDED - -#pragma once - -#include "react/detail/Defs.h" - -/***************************************/ REACT_IMPL_BEGIN /**************************************/ - -enum class UpdateResult -{ - unchanged, - changed, - shifted -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// IReactiveNode -/////////////////////////////////////////////////////////////////////////////////////////////////// -struct IReactiveNode -{ - virtual ~IReactiveNode() = default; - - /// Returns unique type identifier - virtual const char* GetNodeType() const = 0; - - // Note: Could get rid of this ugly ptr by adding a template parameter to the interface - // But that would mean all engine nodes need that template parameter too - so rather cast - virtual UpdateResult Update() = 0; - - /// Input nodes can be manipulated externally. - virtual bool IsInputNode() const = 0; - - /// Output nodes can't have any successors. - virtual bool IsOutputNode() const = 0; - - /// Dynamic nodes may change in topology as a result of tick. - virtual bool IsDynamicNode() const = 0; - - // Number of predecessors. - // This information is statically available at compile time on the graph layer, - // so the engine does not have to calculate it again. - virtual int DependencyCount() const = 0; - - // Heavyweight nodes are worth parallelizing. - virtual bool IsHeavyweight() const = 0; -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// IInputNode -/////////////////////////////////////////////////////////////////////////////////////////////////// -struct IInputNode -{ - virtual ~IInputNode() = default; - - virtual bool ApplyInput(void* turnPtr) = 0; -}; - -/****************************************/ REACT_IMPL_END /***************************************/ - -#endif //REACT_DETAIL_IREACTIVENODE_H_INCLUDED \ No newline at end of file diff --git a/include/react/detail/ReactiveBase.h b/include/react/detail/ReactiveBase.h deleted file mode 100644 index 12dafd82..00000000 --- a/include/react/detail/ReactiveBase.h +++ /dev/null @@ -1,158 +0,0 @@ - -// Copyright Sebastian Jeckel 2016. -// 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) - -#ifndef REACT_DETAIL_REACTIVEBASE_H_INCLUDED -#define REACT_DETAIL_REACTIVEBASE_H_INCLUDED - -#pragma once - -#include "react/detail/Defs.h" - -#include -#include - -#include "react/detail/graph/GraphBase.h" - -/***************************************/ REACT_IMPL_BEGIN /**************************************/ - -template -bool Equals(const L& lhs, const R& rhs) -{ - return lhs == rhs; -} - -template -bool Equals(const std::reference_wrapper& lhs, const std::reference_wrapper& rhs) -{ - return lhs.get() == rhs.get(); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// ReactiveBase -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -class ReactiveBase -{ -public: - using DomainT = typename TNode::DomainT; - - // Default ctor - ReactiveBase() = default; - - // Copy ctor - ReactiveBase(const ReactiveBase&) = default; - - // Move ctor (VS2013 doesn't default generate that yet) - ReactiveBase(ReactiveBase&& other) : - ptr_( std::move(other.ptr_) ) - {} - - // Explicit node ctor - explicit ReactiveBase(std::shared_ptr&& ptr) : - ptr_( std::move(ptr) ) - {} - - // Copy assignment - ReactiveBase& operator=(const ReactiveBase&) = default; - - // Move assignment - ReactiveBase& operator=(ReactiveBase&& other) - { - ptr_.reset(std::move(other)); - return *this; - } - - bool IsValid() const - { - return ptr_ != nullptr; - } - - void SetWeightHint(WeightHint weight) - { - assert(IsValid()); - ptr_->SetWeightHint(weight); - } - -protected: - std::shared_ptr ptr_; - - template - friend const std::shared_ptr& GetNodePtr(const ReactiveBase& node); -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// CopyableReactive -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -class CopyableReactive : public ReactiveBase -{ -public: - CopyableReactive() = default; - - CopyableReactive(const CopyableReactive&) = default; - - CopyableReactive(CopyableReactive&& other) : - CopyableReactive::ReactiveBase( std::move(other) ) - {} - - explicit CopyableReactive(std::shared_ptr&& ptr) : - CopyableReactive::ReactiveBase( std::move(ptr) ) - {} - - CopyableReactive& operator=(const CopyableReactive&) = default; - - CopyableReactive& operator=(CopyableReactive&& other) - { - CopyableReactive::ReactiveBase::operator=(std::move(other)); - return *this; - } - - bool Equals(const CopyableReactive& other) const - { - return this->ptr_ == other.ptr_; - } -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// UniqueReactiveBase -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -class MovableReactive : public ReactiveBase -{ -public: - MovableReactive() = default; - - MovableReactive(MovableReactive&& other) : - MovableReactive::ReactiveBase( std::move(other) ) - {} - - explicit MovableReactive(std::shared_ptr&& ptr) : - MovableReactive::ReactiveBase( std::move(ptr) ) - {} - - MovableReactive& operator=(MovableReactive&& other) - { - MovableReactive::ReactiveBase::operator=(std::move(other)); - return *this; - } - - // Deleted copy ctor and assignment - MovableReactive(const MovableReactive&) = delete; - MovableReactive& operator=(const MovableReactive&) = delete; -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// GetNodePtr -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -const std::shared_ptr& GetNodePtr(const ReactiveBase& node) -{ - return node.ptr_; -} - -/****************************************/ REACT_IMPL_END /***************************************/ - -#endif // REACT_DETAIL_REACTIVEBASE_H_INCLUDED \ No newline at end of file diff --git a/include/react/detail/ReactiveInput.h b/include/react/detail/ReactiveInput.h index ffcbcd6b..dd2d101c 100644 --- a/include/react/detail/ReactiveInput.h +++ b/include/react/detail/ReactiveInput.h @@ -4,6 +4,8 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) +#if 0 + #ifndef REACT_DETAIL_REACTIVEINPUT_H_INCLUDED #define REACT_DETAIL_REACTIVEINPUT_H_INCLUDED @@ -36,17 +38,11 @@ /////////////////////////////////////////////////////////////////////////////////////////////////// /// Forward declarations /////////////////////////////////////////////////////////////////////////////////////////////////// -struct IInputNode; class IObserver; -template -class InputManager; - /////////////////////////////////////////////////////////////////////////////////////////////////// /// Common types & constants /////////////////////////////////////////////////////////////////////////////////////////////////// -using TurnIdT = uint; -using TransactionFuncT = std::function; enum ETransactionFlags { @@ -985,4 +981,6 @@ class DomainSpecificInputManager /****************************************/ REACT_IMPL_END /***************************************/ -#endif // REACT_DETAIL_REACTIVEINPUT_H_INCLUDED \ No newline at end of file +#endif // REACT_DETAIL_REACTIVEINPUT_H_INCLUDED + +#endif \ No newline at end of file diff --git a/include/react/detail/SignalBase.h b/include/react/detail/SignalBase.h deleted file mode 100644 index 9b497136..00000000 --- a/include/react/detail/SignalBase.h +++ /dev/null @@ -1,65 +0,0 @@ - -// Copyright Sebastian Jeckel 2016. -// 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) - -#ifndef REACT_DETAIL_SIGNALBASE_H_INCLUDED -#define REACT_DETAIL_SIGNALBASE_H_INCLUDED - -#pragma once - -#include "react/detail/Defs.h" - -#include - -#include "react/detail/ReactiveBase.h" -#include "react/detail/ReactiveInput.h" -#include "react/detail/graph/SignalNodes.h" - -/***************************************/ REACT_IMPL_BEGIN /**************************************/ - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// SignalBase -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename D, - typename S -> -class SignalBase : public CopyableReactive> -{ -public: - SignalBase() = default; - SignalBase(const SignalBase&) = default; - - template - SignalBase(T&& t) : - SignalBase::CopyableReactive( std::forward(t) ) - {} - -protected: - const S& getValue() const - { - return this->ptr_->ValueRef(); - } - - template - void setValue(T&& newValue) const - { - DomainSpecificInputManager::Instance().AddInput( - *reinterpret_cast*>(this->ptr_.get()), - std::forward(newValue)); - } - - template - void modifyValue(const F& func) const - { - DomainSpecificInputManager::Instance().ModifyInput( - *reinterpret_cast*>(this->ptr_.get()), func); - } -}; - -/****************************************/ REACT_IMPL_END /***************************************/ - -#endif // REACT_DETAIL_SIGNALBASE_H_INCLUDED diff --git a/include/react/detail/graph/AlgorithmNodes.h b/include/react/detail/graph/AlgorithmNodes.h index eb158c4b..4c4fdc35 100644 --- a/include/react/detail/graph/AlgorithmNodes.h +++ b/include/react/detail/graph/AlgorithmNodes.h @@ -81,578 +81,419 @@ struct AddIterateByRefRangeWrapper /////////////////////////////////////////////////////////////////////////////////////////////////// /// IterateNode /////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename D, - typename S, - typename E, - typename TFunc -> -class IterateNode : - public SignalNode +template +class IterateNode : public SignalNode { - using Engine = typename IterateNode::Engine; - public: - template - IterateNode(T&& init, const std::shared_ptr>& events, F&& func) : - IterateNode::SignalNode( std::forward(init) ), + template + IterateNode(const std::shared_ptr& graphPtr, U&& init, const std::shared_ptr>& events, V&& func) : + IterateNode::SignalNode( graphPtr, std::forward(init) ), events_( events ), - func_( std::forward(func) ) + func_( std::forward(func) ) { - Engine::OnNodeCreate(*this); - Engine::OnNodeAttach(*this, *events); + this->RegisterMe(); + this->AttachToMe(events->GetNodeId()); } ~IterateNode() { - Engine::OnNodeDetach(*this, *events_); - Engine::OnNodeDestroy(*this); + this->DetachFromMe(events_->GetNodeId()); + this->UnregisterMe(); } - virtual void Update(void* turnPtr) override + virtual UpdateResult Update(TurnId turnId) override { - using TurnT = typename D::Engine::TurnT; - TurnT& turn = *reinterpret_cast(turnPtr); - - REACT_LOG(D::Log().template Append( - GetObjectId(*this), turn.Id())); - - bool changed = false; - - {// timer - using TimerT = typename IterateNode::ScopedUpdateTimer; - TimerT scopedTimer( *this, events_->Events().size() ); - - S newValue = func_(EventRange( events_->Events() ), this->value_); - - if (! Equals(newValue, this->value_)) - { - this->value_ = std::move(newValue); - changed = true; - } - }// ~timer - - REACT_LOG(D::Log().template Append( - GetObjectId(*this), turn.Id())); + S newValue = func_(EventRange( events_->Events() ), this->Value()); - if (changed) - Engine::OnNodePulse(*this, turn); + if (! Equals(newValue, this->Value())) + { + this->Value() = std::move(newValue); + return UpdateResult::changed; + } else - Engine::OnNodeIdlePulse(*this, turn); + { + return UpdateResult::unchanged; + } } - virtual const char* GetNodeType() const override { return "IterateNode"; } - virtual int DependencyCount() const override { return 1; } + virtual const char* GetNodeType() const override + { return "Iterate"; } + + virtual int GetDependencyCount() const override + { return 1; } private: - std::shared_ptr> events_; + std::shared_ptr> events_; - TFunc func_; + F func_; }; /////////////////////////////////////////////////////////////////////////////////////////////////// /// IterateByRefNode /////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename D, - typename S, - typename E, - typename TFunc -> -class IterateByRefNode : - public SignalNode +template +class IterateByRefNode : public SignalNode { - using Engine = typename IterateByRefNode::Engine; - public: - template - IterateByRefNode(T&& init, const std::shared_ptr>& events, F&& func) : - IterateByRefNode::SignalNode( std::forward(init) ), - func_( std::forward(func) ), + template + IterateByRefNode(const std::shared_ptr& graphPtr, SIn&& init, const std::shared_ptr>& events, FIn&& func) : + IterateByRefNode::SignalNode( graphPtr, std::forward(init) ), + func_( std::forward(func) ), events_( events ) { - Engine::OnNodeCreate(*this); - Engine::OnNodeAttach(*this, *events); + this->RegisterMe(); + this->AttachToMe(events->GetNodeId()); } ~IterateByRefNode() { - Engine::OnNodeDetach(*this, *events_); - Engine::OnNodeDestroy(*this); + this->DetachFromMe(events_->GetNodeId()); + this->UnregisterMe(); } - virtual void Update(void* turnPtr) override + virtual UpdateResult Update(TurnId turnId) override { - using TurnT = typename D::Engine::TurnT; - TurnT& turn = *reinterpret_cast(turnPtr); - - REACT_LOG(D::Log().template Append( - GetObjectId(*this), turn.Id())); - - {// timer - using TimerT = typename IterateByRefNode::ScopedUpdateTimer; - TimerT scopedTimer( *this, events_->Events().size() ); - - func_(EventRange( events_->Events() ), this->value_); - - }// ~timer - - REACT_LOG(D::Log().template Append( - GetObjectId(*this), turn.Id())); + func_(EventRange( events_->Events() ), this->Value()); // Always assume change - Engine::OnNodePulse(*this, turn); + return UpdateResult::changed; } - virtual const char* GetNodeType() const override { return "IterateByRefNode"; } - virtual int DependencyCount() const override { return 1; } + virtual const char* GetNodeType() const override + { return "IterateByRefNode"; } + + virtual int GetDependencyCount() const override + { return 1; } protected: - TFunc func_; + F func_; - std::shared_ptr> events_; + std::shared_ptr> events_; }; /////////////////////////////////////////////////////////////////////////////////////////////////// /// SyncedIterateNode /////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename D, - typename S, - typename E, - typename TFunc, - typename ... TDepValues -> -class SyncedIterateNode : - public SignalNode +template +class SyncedIterateNode : public SignalNode { - using Engine = typename SyncedIterateNode::Engine; - public: - template - SyncedIterateNode(T&& init, const std::shared_ptr>& events, F&& func, - const std::shared_ptr>& ... deps) : - SyncedIterateNode::SignalNode( std::forward(init) ), + template + SyncedIterateNode(const std::shared_ptr& graphPtr, SIn&& init, const std::shared_ptr>& events, FIn&& func, const std::shared_ptr>& ... syncs) : + SyncedIterateNode::SignalNode( graphPtr, std::forward(init) ), events_( events ), - func_( std::forward(func) ), - deps_( deps ... ) + func_( std::forward(func) ), + syncHolder_( syncs ... ) { - Engine::OnNodeCreate(*this); - Engine::OnNodeAttach(*this, *events); - REACT_EXPAND_PACK(Engine::OnNodeAttach(*this, *deps)); + this->RegisterMe(); + this->AttachToMe(dep->GetNodeId()); + REACT_EXPAND_PACK(this->AttachToMe(syncs->GetNodeId())); } ~SyncedIterateNode() { - Engine::OnNodeDetach(*this, *events_); - - apply( - DetachFunctor>...>( *this ), - deps_); - - Engine::OnNodeDestroy(*this); + apply([this] (const auto& ... syncs) { REACT_EXPAND_PACK(this->DetachFromMe(syncs->GetNodeId())); }, syncHolder_); + this->DetachFromMe(dep_->GetNodeId()); + this->UnregisterMe(); } - virtual void Update(void* turnPtr) override + virtual UpdateResult Update(TurnId turnId) override { - using TurnT = typename D::Engine::TurnT; - TurnT& turn = *reinterpret_cast(turnPtr); - events_->SetCurrentTurn(turn); - bool changed = false; - - REACT_LOG(D::Log().template Append( - GetObjectId(*this), turn.Id())); - - if (! events_->Events().empty()) - {// timer - using TimerT = typename SyncedIterateNode::ScopedUpdateTimer; - TimerT scopedTimer( *this, events_->Events().size() ); - - S newValue = apply( - [this] (const std::shared_ptr>& ... args) - { - return func_(EventRange( events_->Events() ), this->value_, args->ValueRef() ...); - }, - deps_); - - if (! Equals(newValue, this->value_)) + S newValue = apply( + [this] (const auto& ... syncs) { - changed = true; - this->value_ = std::move(newValue); - } - }// ~timer - - REACT_LOG(D::Log().template Append( - GetObjectId(*this), turn.Id())); + return func_(EventRange( events_->Events() ), this->Value(), syncs->Value() ...); + }, + syncHolder_); - if (changed) - Engine::OnNodePulse(*this, turn); + if (! Equals(newValue, this->Value())) + { + this->Value() = std::move(newValue); + return UpdateResult::changed; + } else - Engine::OnNodeIdlePulse(*this, turn); + { + return UpdateResult::unchanged; + } } - virtual const char* GetNodeType() const override { return "SyncedIterateNode"; } - virtual int DependencyCount() const override { return 1 + sizeof...(TDepValues); } + virtual const char* GetNodeType() const override + { return "SyncedIterate"; } -private: - using DepHolderT = std::tuple>...>; + virtual int GetDependencyCount() const override + { return 1 + sizeof...(TSyncs); } - std::shared_ptr> events_; +private: + std::shared_ptr> events_; - TFunc func_; - DepHolderT deps_; + F func_; + + std::tuple>...> syncHolder_; }; /////////////////////////////////////////////////////////////////////////////////////////////////// /// SyncedIterateByRefNode /////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename D, - typename S, - typename E, - typename TFunc, - typename ... TDepValues -> -class SyncedIterateByRefNode : - public SignalNode +template +class SyncedIterateByRefNode : public SignalNode { - using Engine = typename SyncedIterateByRefNode::Engine; - public: - template - SyncedIterateByRefNode(T&& init, const std::shared_ptr>& events, F&& func, - const std::shared_ptr>& ... deps) : - SyncedIterateByRefNode::SignalNode( std::forward(init) ), + template + SyncedIterateByRefNode(const std::shared_ptr& graphPtr, SIn&& init, const std::shared_ptr>& events, FIn&& func, const std::shared_ptr>& ... syncs) : + SyncedIterateByRefNode::SignalNode( graphPtr, std::forward(init) ), events_( events ), - func_( std::forward(func) ), - deps_( deps ... ) + func_( std::forward(func) ), + syncHolder_( syncs ... ) { - Engine::OnNodeCreate(*this); - Engine::OnNodeAttach(*this, *events); - REACT_EXPAND_PACK(Engine::OnNodeAttach(*this, *deps)); + this->RegisterMe(); + this->AttachToMe(dep->GetNodeId()); + REACT_EXPAND_PACK(this->AttachToMe(syncs->GetNodeId())); } ~SyncedIterateByRefNode() { - Engine::OnNodeDetach(*this, *events_); - - apply( - DetachFunctor>...>( *this ), - deps_); - - Engine::OnNodeDestroy(*this); + apply([this] (const auto& ... syncs) { REACT_EXPAND_PACK(this->DetachFromMe(syncs->GetNodeId())); }, syncHolder_); + this->DetachFromMe(dep_->GetNodeId()); + this->UnregisterMe(); } - virtual void Update(void* turnPtr) override + virtual UpdateResult Update(TurnId turnId) override { - using TurnT = typename D::Engine::TurnT; - TurnT& turn = *reinterpret_cast(turnPtr); - events_->SetCurrentTurn(turn); bool changed = false; - REACT_LOG(D::Log().template Append( - GetObjectId(*this), turn.Id())); - if (! events_->Events().empty()) - {// timer - using TimerT = typename SyncedIterateByRefNode::ScopedUpdateTimer; - TimerT scopedTimer( *this, events_->Events().size() ); - + { apply( - [this] (const std::shared_ptr>& ... args) + [this] (const auto& ... args) { - func_(EventRange( events_->Events() ), this->value_, args->ValueRef() ...); + func_(EventRange( events_->Events() ), this->Value(), args->Value() ...); }, deps_); - changed = true; - }// ~timer - - REACT_LOG(D::Log().template Append( - GetObjectId(*this), turn.Id())); - - if (changed) - Engine::OnNodePulse(*this, turn); + return UpdateResult::changed; + } else - Engine::OnNodeIdlePulse(*this, turn); + { + return UpdateResult::unchanged; + } } - virtual const char* GetNodeType() const override { return "SyncedIterateByRefNode"; } - virtual int DependencyCount() const override { return 1 + sizeof...(TDepValues); } + virtual const char* GetNodeType() const override + { return "SyncedIterateByRef"; } -private: - using DepHolderT = std::tuple>...>; + virtual int GetDependencyCount() const override + { return 1 + sizeof...(TSyncs); } - std::shared_ptr> events_; +private: + std::shared_ptr> events_; - TFunc func_; - DepHolderT deps_; + F func_; + + std::tuple>...> syncHolder_; }; /////////////////////////////////////////////////////////////////////////////////////////////////// /// HoldNode /////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename D, - typename S -> -class HoldNode : public SignalNode +template +class HoldNode : public SignalNode { - using Engine = typename HoldNode::Engine; - public: - template - HoldNode(T&& init, const std::shared_ptr>& events) : - HoldNode::SignalNode( std::forward(init) ), + template + HoldNode(const std::shared_ptr& graphPtr, TIn&& init, const std::shared_ptr>& events) : + HoldNode::SignalNode( graphPtr, std::forward(init) ), events_( events ) { - Engine::OnNodeCreate(*this); - Engine::OnNodeAttach(*this, *events_); + this->RegisterMe(); + this->AttachToMe(events->GetNodeId()); } ~HoldNode() { - Engine::OnNodeDetach(*this, *events_); - Engine::OnNodeDestroy(*this); + this->DetachFromMe(events_->GetNodeId()); + this->UnregisterMe(); } - virtual const char* GetNodeType() const override { return "HoldNode"; } + virtual const char* GetNodeType() const override + { return "HoldNode"; } - virtual void Update(void* turnPtr) override + virtual UpdateResult Update(TurnId turnId) override { - using TurnT = typename D::Engine::TurnT; - TurnT& turn = *reinterpret_cast(turnPtr); - - REACT_LOG(D::Log().template Append( - GetObjectId(*this), turn.Id())); - bool changed = false; if (! events_->Events().empty()) { const S& newValue = events_->Events().back(); - if (! Equals(newValue, this->value_)) + if (! Equals(newValue, this->Value())) { changed = true; - this->value_ = newValue; + this->Value() = newValue; } } - REACT_LOG(D::Log().template Append( - GetObjectId(*this), turn.Id())); - if (changed) - Engine::OnNodePulse(*this, turn); + return UpdateResult::changed; else - Engine::OnNodeIdlePulse(*this, turn); + return UpdateResult::unchanged; } - virtual int DependencyCount() const override { return 1; } + virtual int GetDependencyCount() const override + { return 1; } private: - const std::shared_ptr> events_; + const std::shared_ptr> events_; }; /////////////////////////////////////////////////////////////////////////////////////////////////// /// SnapshotNode /////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename D, - typename S, - typename E -> -class SnapshotNode : public SignalNode +template +class SnapshotNode : public SignalNode { - using Engine = typename SnapshotNode::Engine; - public: - SnapshotNode(const std::shared_ptr>& target, - const std::shared_ptr>& trigger) : - SnapshotNode::SignalNode( target->ValueRef() ), + SnapshotNode(const std::shared_ptr& graphPtr, const std::shared_ptr>& target, const std::shared_ptr>& trigger) : + SnapshotNode::SignalNode( graphPtr, target->Value() ), target_( target ), trigger_( trigger ) { - Engine::OnNodeCreate(*this); - Engine::OnNodeAttach(*this, *target_); - Engine::OnNodeAttach(*this, *trigger_); + this->RegisterMe(); + this->AttachToMe(target->GetNodeId()); + this->AttachToMe(trigger->GetNodeId()); } ~SnapshotNode() { - Engine::OnNodeDetach(*this, *target_); - Engine::OnNodeDetach(*this, *trigger_); - Engine::OnNodeDestroy(*this); + this->DetachFromMe(trigger_->GetNodeId()); + this->DetachFromMe(target_->GetNodeId()); + this->UnregisterMe(); } - virtual void Update(void* turnPtr) override + virtual UpdateResult Update(TurnId turnId) override { - using TurnT = typename D::Engine::TurnT; - TurnT& turn = *reinterpret_cast(turnPtr); - - trigger_->SetCurrentTurn(turn); - - REACT_LOG(D::Log().template Append( - GetObjectId(*this), turn.Id())); + trigger_->SetCurrentTurn(turnId); bool changed = false; if (! trigger_->Events().empty()) { - const S& newValue = target_->ValueRef(); + const S& newValue = target_->Value(); - if (! Equals(newValue, this->value_)) + if (! Equals(newValue, this->Value())) { changed = true; - this->value_ = newValue; + this->Value() = newValue; } } - REACT_LOG(D::Log().template Append( - GetObjectId(*this), turn.Id())); - if (changed) - Engine::OnNodePulse(*this, turn); + return UpdateResult::changed; else - Engine::OnNodeIdlePulse(*this, turn); + return UpdateResult::unchanged; } - virtual const char* GetNodeType() const override { return "SnapshotNode"; } - virtual int DependencyCount() const override { return 2; } + virtual const char* GetNodeType() const override + { return "Snapshot"; } + + virtual int GetDependencyCount() const override + { return 2; } private: - const std::shared_ptr> target_; - const std::shared_ptr> trigger_; + std::shared_ptr> target_; + std::shared_ptr> trigger_; }; /////////////////////////////////////////////////////////////////////////////////////////////////// /// MonitorNode /////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename D, - typename E -> -class MonitorNode : public EventStreamNode +template +class MonitorNode : public EventStreamNode { - using Engine = typename MonitorNode::Engine; - public: - MonitorNode(const std::shared_ptr>& target) : - MonitorNode::EventStreamNode( ), + MonitorNode(const std::shared_ptr& graphPtr, const std::shared_ptr>& target) : + MonitorNode::EventStreamNode( graphPtr ), target_( target ) { - Engine::OnNodeCreate(*this); - Engine::OnNodeAttach(*this, *target_); + this->RegisterMe(); + this->AttachToMe(target->GetNodeId()); } ~MonitorNode() { - Engine::OnNodeDetach(*this, *target_); - Engine::OnNodeDestroy(*this); + this->DetachFromMe(target_->GetNodeId()); + this->UnregisterMe(); } - virtual void Update(void* turnPtr) override + virtual UpdateResult Update(TurnId turnId) override { - using TurnT = typename D::Engine::TurnT; - TurnT& turn = *reinterpret_cast(turnPtr); - this->SetCurrentTurn(turn, true); - REACT_LOG(D::Log().template Append( - GetObjectId(*this), turn.Id())); - - this->events_.push_back(target_->ValueRef()); - - REACT_LOG(D::Log().template Append( - GetObjectId(*this), turn.Id())); + this->Events().push_back(target_->Value()); - if (! this->events_.empty()) - Engine::OnNodePulse(*this, turn); - else - Engine::OnNodeIdlePulse(*this, turn); + return UpdateResult::changed; } - virtual const char* GetNodeType() const override { return "MonitorNode"; } - virtual int DependencyCount() const override { return 1; } + virtual const char* GetNodeType() const override + { return "Monitor"; } + + virtual int GetDependencyCount() const override + { return 1; } private: - const std::shared_ptr> target_; + std::shared_ptr> target_; }; /////////////////////////////////////////////////////////////////////////////////////////////////// /// PulseNode /////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename D, - typename S, - typename E -> -class PulseNode : public EventStreamNode +template +class PulseNode : public EventStreamNode { - using Engine = typename PulseNode::Engine; - public: - PulseNode(const std::shared_ptr>& target, - const std::shared_ptr>& trigger) : - PulseNode::EventStreamNode( ), + PulseNode(const std::shared_ptr& graphPtr, const std::shared_ptr>& target, const std::shared_ptr>& trigger) : + PulseNode::EventStreamNode( graphPtr ), target_( target ), trigger_( trigger ) { - Engine::OnNodeCreate(*this); - Engine::OnNodeAttach(*this, *target_); - Engine::OnNodeAttach(*this, *trigger_); + this->RegisterMe(); + this->AttachToMe(target->GetNodeId()); + this->AttachToMe(trigger->GetNodeId()); } ~PulseNode() { - Engine::OnNodeDetach(*this, *target_); - Engine::OnNodeDetach(*this, *trigger_); - Engine::OnNodeDestroy(*this); + this->DetachFromMe(trigger_->GetNodeId()); + this->DetachFromMe(target_->GetNodeId()); + this->UnregisterMe(); } - virtual void Update(void* turnPtr) override + virtual UpdateResult Update(TurnId turnId) override { - typedef typename D::Engine::TurnT TurnT; - TurnT& turn = *reinterpret_cast(turnPtr); - this->SetCurrentTurn(turn, true); trigger_->SetCurrentTurn(turn); - REACT_LOG(D::Log().template Append( - GetObjectId(*this), turn.Id())); - - for (uint i=0; iEvents().size(); i++) - this->events_.push_back(target_->ValueRef()); + for (size_t i=0; iEvents().size(); i++) + this->Events().push_back(target_->Value()); - REACT_LOG(D::Log().template Append( - GetObjectId(*this), turn.Id())); - - if (! this->events_.empty()) - Engine::OnNodePulse(*this, turn); + if (! this->Events().empty()) + return UpdateResult::changed; else - Engine::OnNodeIdlePulse(*this, turn); + return UpdateResult::unchanged; } - virtual const char* GetNodeType() const override { return "PulseNode"; } - virtual int DependencyCount() const override { return 2; } + virtual const char* GetNodeType() const override + { return "PulseNode"; } + + virtual int GetDependencyCount() const override + { return 2; } private: - const std::shared_ptr> target_; - const std::shared_ptr> trigger_; + const std::shared_ptr> target_; + const std::shared_ptr> trigger_; }; /****************************************/ REACT_IMPL_END /***************************************/ diff --git a/include/react/detail/graph/ContinuationNodes.h b/include/react/detail/graph/ContinuationNodes.h deleted file mode 100644 index 6d494453..00000000 --- a/include/react/detail/graph/ContinuationNodes.h +++ /dev/null @@ -1,351 +0,0 @@ - -// Copyright Sebastian Jeckel 2016. -// 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) - -#ifndef REACT_DETAIL_GRAPH_CONTINUATIONNODES_H_INCLUDED -#define REACT_DETAIL_GRAPH_CONTINUATIONNODES_H_INCLUDED - -#pragma once - -#include "react/detail/Defs.h" - -#include -#include -#include - -#include "GraphBase.h" - -#include "react/detail/ReactiveInput.h" - -/***************************************/ REACT_IMPL_BEGIN /**************************************/ - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Forward declarations -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -class SignalNode; - -template -class EventStreamNode; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// AddContinuationRangeWrapper -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -struct AddContinuationRangeWrapper -{ - AddContinuationRangeWrapper(const AddContinuationRangeWrapper& other) = default; - - AddContinuationRangeWrapper(AddContinuationRangeWrapper&& other) : - MyFunc( std::move(other.MyFunc) ) - {} - - template - < - typename FIn, - class = typename DisableIfSame::type - > - explicit AddContinuationRangeWrapper(FIn&& func) : - MyFunc( std::forward(func) ) - {} - - void operator()(EventRange range, const TArgs& ... args) - { - for (const auto& e : range) - MyFunc(e, args ...); - } - - F MyFunc; -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// ContinuationNode -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -class ContinuationNode : public NodeBase -{ -public: - ContinuationNode(TransactionFlagsT turnFlags) : - turnFlags_( turnFlags ) - {} - - virtual bool IsOutputNode() const { return true; } - -protected: - TransactionFlagsT turnFlags_; -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// SignalContinuationNode -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename D, - typename DOut, - typename S, - typename TFunc -> -class SignalContinuationNode : public ContinuationNode -{ - using Engine = typename SignalContinuationNode::Engine; - -public: - template - SignalContinuationNode(TransactionFlagsT turnFlags, - const std::shared_ptr>& trigger, F&& func) : - SignalContinuationNode::ContinuationNode( turnFlags ), - trigger_( trigger ), - func_( std::forward(func) ) - { - Engine::OnNodeCreate(*this); - Engine::OnNodeAttach(*this, *trigger); - } - - ~SignalContinuationNode() - { - Engine::OnNodeDestroy(*this); - } - - virtual const char* GetNodeType() const override { return "SignalContinuationNode"; } - virtual int DependencyCount() const override { return 1; } - - virtual void Update(void* turnPtr) override - { -#ifdef REACT_ENABLE_LOGGING - using TurnT = typename D::Engine::TurnT; - TurnT& turn = *reinterpret_cast(turnPtr); -#endif - - REACT_LOG(D::Log().template Append( - GetObjectId(*this), turn.Id())); - - auto& storedValue = trigger_->ValueRef(); - auto& storedFunc = func_; - - TransactionFuncT cont - ( - // Copy value and func - [storedFunc,storedValue] () mutable - { - storedFunc(storedValue); - } - ); - - DomainSpecificInputManager::Instance() - .StoreContinuation( - DomainSpecificInputManager::Instance(), - this->turnFlags_, - std::move(cont)); - - REACT_LOG(D::Log().template Append( - GetObjectId(*this), turn.Id())); - } - -private: - std::shared_ptr> trigger_; - - TFunc func_; -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// EventContinuationNode -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename D, - typename DOut, - typename E, - typename TFunc -> -class EventContinuationNode : public ContinuationNode -{ - using Engine = typename EventContinuationNode::Engine; - -public: - template - EventContinuationNode(TransactionFlagsT turnFlags, - const std::shared_ptr>& trigger, F&& func) : - EventContinuationNode::ContinuationNode( turnFlags ), - trigger_( trigger ), - func_( std::forward(func) ) - { - Engine::OnNodeCreate(*this); - Engine::OnNodeAttach(*this, *trigger); - } - - ~EventContinuationNode() - { - Engine::OnNodeDestroy(*this); - } - - virtual const char* GetNodeType() const override { return "EventContinuationNode"; } - virtual int DependencyCount() const override { return 1; } - - virtual void Update(void* turnPtr) override - { -#ifdef REACT_ENABLE_LOGGING - using TurnT = typename D::Engine::TurnT; - TurnT& turn = *reinterpret_cast(turnPtr); -#endif - - REACT_LOG(D::Log().template Append( - GetObjectId(*this), turn.Id())); - - auto& storedEvents = trigger_->Events(); - auto& storedFunc = func_; - - TransactionFuncT cont - ( - // Copy events and func - [storedFunc,storedEvents] () mutable - { - storedFunc(EventRange( storedEvents )); - } - ); - - DomainSpecificInputManager::Instance() - .StoreContinuation( - DomainSpecificInputManager::Instance(), - this->turnFlags_, - std::move(cont)); - - REACT_LOG(D::Log().template Append( - GetObjectId(*this), turn.Id())); - } - -private: - std::shared_ptr> trigger_; - - TFunc func_; -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// SyncedContinuationNode -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename D, - typename DOut, - typename E, - typename TFunc, - typename ... TDepValues -> -class SyncedContinuationNode : public ContinuationNode -{ - using Engine = typename SyncedContinuationNode::Engine; - - using ValueTupleT = std::tuple; - - struct TupleBuilder_ - { - ValueTupleT operator()(const std::shared_ptr>& ... deps) - { - return ValueTupleT(deps->ValueRef() ...); - } - }; - - struct EvalFunctor_ - { - EvalFunctor_(const E& e, TFunc& f) : - MyEvent( e ), - MyFunc( f ) - {} - - void operator()(const TDepValues& ... vals) - { - MyFunc(MyEvent, vals ...); - } - - const E& MyEvent; - TFunc& MyFunc; - }; - -public: - template - SyncedContinuationNode(TransactionFlagsT turnFlags, - const std::shared_ptr>& trigger, F&& func, - const std::shared_ptr>& ... deps) : - SyncedContinuationNode::ContinuationNode( turnFlags ), - trigger_( trigger ), - func_( std::forward(func) ), - deps_( deps ... ) - { - Engine::OnNodeCreate(*this); - Engine::OnNodeAttach(*this, *trigger); - - REACT_EXPAND_PACK(Engine::OnNodeAttach(*this, *deps)); - } - - ~SyncedContinuationNode() - { - Engine::OnNodeDetach(*this, *trigger_); - - apply( - DetachFunctor>...>( *this ), - deps_); - - Engine::OnNodeDestroy(*this); - } - - virtual const char* GetNodeType() const override { return "SyncedContinuationNode"; } - virtual int DependencyCount() const override { return 1 + sizeof...(TDepValues); } - - virtual void Update(void* turnPtr) override - { - using TurnT = typename D::Engine::TurnT; - TurnT& turn = *reinterpret_cast(turnPtr); - - REACT_LOG(D::Log().template Append( - GetObjectId(*this), turn.Id())); - - // Update of this node could be triggered from deps, - // so make sure source doesnt contain events from last turn - trigger_->SetCurrentTurn(turn); - - auto& storedEvents = trigger_->Events(); - auto& storedFunc = func_; - - // Copy values to tuple - ValueTupleT storedValues = apply(TupleBuilder_( ), deps_); - - // Note: MSVC error, if using () initialization. - // Probably a compiler bug. - TransactionFuncT cont - { - // Copy events, func, value tuple (note: 2x copy) - [storedFunc,storedEvents,storedValues] () mutable - { - apply( - [&storedFunc,&storedEvents] (const TDepValues& ... vals) - { - storedFunc(EventRange( storedEvents ), vals ...); - }, - storedValues); - } - }; - - DomainSpecificInputManager::Instance() - .StoreContinuation( - DomainSpecificInputManager::Instance(), - this->turnFlags_, - std::move(cont)); - - REACT_LOG(D::Log().template Append( - GetObjectId(*this), turn.Id())); - } - -private: - using DepHolderT = std::tuple>...>; - - std::shared_ptr> trigger_; - - TFunc func_; - DepHolderT deps_; -}; - -/****************************************/ REACT_IMPL_END /***************************************/ - -#endif // REACT_DETAIL_GRAPH_CONTINUATIONNODES_H_INCLUDED \ No newline at end of file diff --git a/include/react/detail/graph/EventNodes.h b/include/react/detail/graph/EventNodes.h index 00e35cbf..a68df789 100644 --- a/include/react/detail/graph/EventNodes.h +++ b/include/react/detail/graph/EventNodes.h @@ -15,13 +15,55 @@ #include #include #include +#include -#include "tbb/spin_mutex.h" +//#include "tbb/spin_mutex.h" #include "GraphBase.h" -#include "react/common/Concurrency.h" #include "react/common/Types.h" +/*****************************************/ REACT_BEGIN /*****************************************/ + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// Iterators for event processing +/////////////////////////////////////////////////////////////////////////////////////////////////// +template +class EventRange +{ +public: + using const_iterator = typename std::vector::const_iterator; + using size_type = typename std::vector::size_type; + + EventRange() = delete; + + EventRange(const EventRange&) = default; + EventRange& operator=(const EventRange&) = default; + + explicit EventRange(const std::vector& data) : + data_( data ) + { } + + const_iterator begin() const + { return data_.begin(); } + + const_iterator end() const + { return data_.end(); } + + size_type GetSize() const + { return data_.size(); } + + bool IsEmpty() const + { return data_.empty(); } + +private: + const std::vector& data_; +}; + +template +using EventSink = std::back_insert_iterator>; + +/******************************************/ REACT_END /******************************************/ + /***************************************/ REACT_IMPL_BEGIN /**************************************/ /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -39,27 +81,27 @@ class EventStreamNode : public NodeBase public: using StorageType = std::vector; - EventStreamNode(IReactiveGroup* group) : NodeBase( group ) - { } - - EventStreamNode(NodeBase&&) = default; - EventStreamNode& operator=(NodeBase&&) = default; + EventStreamNode(EventStreamNode&&) = default; + EventStreamNode& operator=(EventStreamNode&&) = default; - EventStreamNode(const NodeBase&) = delete; - EventStreamNode& operator=(const NodeBase&) = delete; + EventStreamNode(const EventStreamNode&) = delete; + EventStreamNode& operator=(const EventStreamNode&) = delete; - void SetCurrentTurn(const TurnT& turn, bool forceUpdate = false, bool noClear = false) + void SetCurrentTurn(TurnId turnId, bool forceUpdate = false, bool noClear = false) { - this->AccessBufferForClearing([&] { - if (curTurnId_ != turn.Id() || forceUpdate) - { - curTurnId_ = turn.Id(); - if (!noClear) - events_.clear(); - } - }); + //this->AccessBufferForClearing([&] { + // if (curTurnId_ != turn.Id() || forceUpdate) + // { + // curTurnId_ = turn.Id(); + // if (!noClear) + // events_.clear(); + // } + //}); } + explicit EventStreamNode(const std::shared_ptr& graphPtr) : NodeBase( graphPtr ) + { } + StorageType& Events() { return events_; } @@ -77,10 +119,10 @@ class EventStreamNode : public NodeBase /// EventSourceNode /////////////////////////////////////////////////////////////////////////////////////////////////// template -class EventSourceNode : public EventStreamNode, public IInputNode +class EventSourceNode : public EventStreamNode { public: - EventSourceNode(IReactiveGroup* group) : EventSourceNode::EventStreamNode( group ) + EventSourceNode(const std::shared_ptr& graphPtr) : EventSourceNode::EventStreamNode( graphPtr ) { this->RegisterMe(); } ~EventSourceNode() @@ -92,41 +134,35 @@ class EventSourceNode : public EventStreamNode, public IInputNode virtual bool IsInputNode() const override { return true; } - virtual int DependencyCount() const override + virtual int GetDependencyCount() const override { return 0; } - virtual void Update(void* turnPtr) override - { REACT_ASSERT(false, "Updated EventSourceNode\n"); } - - template - void AddInput(V&& v) + virtual UpdateResult Update(TurnId turnId) override { - // Clear input from previous turn - if (changedFlag_) + if (this->Events().size() > 0 && !changedFlag_) { - changedFlag_ = false; - this->events_.clear(); + this->SetCurrentTurn(turnId, true, true); + changedFlag_ = true; + + return UpdateResult::changed; + } + else + { + return UpdateResult::unchanged; } - - this->events_.push_back(std::forward(v)); } - virtual bool ApplyInput(void* turnPtr) override + template + void EmitValue(U&& value) { - if (this->events_.size() > 0 && !changedFlag_) - { - using TurnT = typename D::Engine::TurnT; - TurnT& turn = *reinterpret_cast(turnPtr); - - this->SetCurrentTurn(turn, true, true); - changedFlag_ = true; - Engine::OnInputChange(*this, turn); - return true; - } - else + // Clear input from previous turn + if (changedFlag_) { - return false; + changedFlag_ = false; + this->Events().clear(); } + + this->Events().push_back(std::forward(value)); } private: @@ -140,8 +176,8 @@ template class EventMergeNode : public EventStreamNode { public: - EventMergeNode(IReactiveGroup* group, const std::shared_ptr>& ... deps) : - EventMergeNode::EventStreamNode( group ), + EventMergeNode(const std::shared_ptr& graphPtr, const std::shared_ptr>& ... deps) : + EventMergeNode::EventStreamNode( graphPtr ), depHolder_( deps ... ) { this->RegisterMe(); @@ -154,9 +190,9 @@ class EventMergeNode : public EventStreamNode this->UnregisterMe(); } - virtual UpdateResult Update() override + virtual UpdateResult Update(TurnId turnId) override { - // this->SetCurrentTurn(turn, true); + this->SetCurrentTurn(turnId, true); apply([this] (const auto& ... deps) { REACT_EXPAND_PACK(MergeFromDep(deps)); }, depHolder_); @@ -169,115 +205,18 @@ class EventMergeNode : public EventStreamNode virtual const char* GetNodeType() const override { return "EventMerge"; } - virtual int DependencyCount() const override - { return sizeof...(Es); } + virtual int GetDependencyCount() const override + { return sizeof...(TIns); } private: template - void MergeFromDep(const std::shared_ptr& other) + void MergeFromDep(const std::shared_ptr>& other) { //arg->SetCurrentTurn(turn); this->Events().insert(this->Events().end(), other->Events().begin(), other->Events().end()); } - std::tuple ...> depHolder_; -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// EventTransformNode -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -class EventTransformNode : public EventStreamNode -{ -public: - template - EventTransformNode(IReactiveGroup* group, const std::shared_ptr>& dep, U&& func) : - EventTransformNode::EventStreamNode( group ), - dep_( dep ), - func_( std::forward(func) ) - { - this->RegisterMe(); - this->AttachToMe(dep->GetNodeId()); - } - - ~EventTransformNode() - { - this->DetachFromMe(dep_->GetNodeId()); - this->UnregisterMe(); - } - - virtual UpdateResult Update() override - { - // this->SetCurrentTurn(turn, true); - - for (const auto& v : dep_->Events()) - this->Events().push_back(func_(v)); - - if (! this->Events().empty()) - return UpdateResult::changed; - else - return UpdateResult::unchanged; - } - - virtual const char* GetNodeType() const override - { return "EventTransform"; } - - virtual int DependencyCount() const override - { return 1; } - -private: - std::shared_ptr dep_; - - F func_; -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// EventFilterNode -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -class EventFilterNode : public EventStreamNode -{ -public: - template - EventFilterNode(IReactiveGroup* group, const std::shared_ptr>& dep, U&& pred) : - EventFilterNode::EventStreamNode( group ), - dep_( dep ), - pred_( std::forward(pred) ) - { - this->RegisterMe(); - this->AttachToMe(dep->GetNodeId()); - } - - ~EventFilterNode() - { - this->DetachFromMe(dep_->GetNodeId()); - this->UnregisterMe(); - } - - virtual UpdateResult Update() override - { - // this->SetCurrentTurn(turn, true); - - for (const auto& v : dep_->Events()) - if (pred_(v)) - this->Events().push_back(v); - - if (! this->Events().empty()) - return UpdateResult::changed; - else - return UpdateResult::unchanged; - } - - virtual const char* GetNodeType() const override - { return "EventFilter"; } - - virtual int DependencyCount() const override - { return 1; } - -private: - std::shared_ptr dep_; - - F pred_; + std::tuple> ...> depHolder_; }; /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -287,8 +226,8 @@ template class EventFlattenNode : public EventStreamNode { public: - EventFlattenNode(IReactiveGroup* group, const std::shared_ptr>& outer, const std::shared_ptr>& inner) : - EventFlattenNode::EventStreamNode( group ), + EventFlattenNode(const std::shared_ptr& graphPtr, const std::shared_ptr>& outer, const std::shared_ptr>& inner) : + EventFlattenNode::EventStreamNode( graphPtr ), outer_( outer ), inner_( inner ) { @@ -310,19 +249,19 @@ class EventFlattenNode : public EventStreamNode virtual bool IsDynamicNode() const override { return true; } - virtual int DependencyCount() const override + virtual int GetDependencyCount() const override { return 2; } - virtual UpdateResult Update() override + virtual UpdateResult Update(TurnId turnId) override { - // this->SetCurrentTurn(turn, true); - // inner_->SetCurrentTurn(turn); + this->SetCurrentTurn(turnId, true); + inner_->SetCurrentTurn(turnId); - auto newInner = GetNodePtr(outer_->ValueRef()); + auto newInner = GetNodePtr(outer_->Value()); if (newInner != inner_) { - newInner->SetCurrentTurn(turn); + newInner->SetCurrentTurn(turnId); // Topology has been changed auto oldInner = inner_; @@ -347,121 +286,6 @@ class EventFlattenNode : public EventStreamNode std::shared_ptr> inner_; }; -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// SyncedEventTransformNode -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -class SyncedEventTransformNode : public EventStreamNode -{ -public: - template - SyncedEventTransformNode(IReactiveGroup* group, const std::shared_ptr>& dep, U&& func, const std::shared_ptr>& ... syncs) : - SyncedEventTransformNode::EventStreamNode( group ), - dep_( dep ), - func_( std::forward(func) ), - syncs_( syncs ... ) - { - this->RegisterMe(); - this->AttachToMe(dep->GetNodeId()); - REACT_EXPAND_PACK(this->AttachToMe(syncs->GetNodeId())); - } - - ~SyncedEventTransformNode() - { - apply([this] (const auto& ... syncs) { REACT_EXPAND_PACK(this->DetachFromMe(syncs->GetNodeId())); }, syncHolder_); - this->DetachFromMe(dep_->GetNodeId()); - this->UnregisterMe(); - } - - virtual UpdateResult Update() override - { - //this->SetCurrentTurn(turn, true); - - // Update of this node could be triggered from deps, - // so make sure source doesnt contain events from last turn - // source_->SetCurrentTurn(turn); - - for (const auto& e : dep_->Events()) - this->Events().push_back(apply([this, &e] (const auto& ... syncs) { return this->func_(e, syncs->ValueRef() ...); }, syncHolder_)); - - if (! this->Events().empty()) - return UpdateResult::changed; - else - return UpdateResult::unchanged; - } - - virtual const char* GetNodeType() const override - { return "SyncedEventTransform"; } - - virtual int DependencyCount() const override - { return 1 + sizeof...(TSyncs); } - -private: - std::shared_ptr> dep_; - - F func_; - - std::tuple>...> syncHolder_; -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// SyncedEventFilterNode -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -class SyncedEventFilterNode : public EventStreamNode -{ -public: - template - SyncedEventFilterNode(IReactiveGroup* group, const std::shared_ptr>& dep, U&& pred, const std::shared_ptr>& ... syncs) : - SyncedEventFilterNode::EventStreamNode( group ), - dep_( dep ), - pred_( std::forward(pred) ), - syncs_( syncs ... ) - { - this->RegisterMe(); - this->AttachToMe(dep->GetNodeId()); - REACT_EXPAND_PACK(this->AttachToMe(syncs->GetNodeId())); - } - - ~SyncedEventFilterNode() - { - apply([this] (const auto& ... syncs) { REACT_EXPAND_PACK(this->DetachFromMe(syncs->GetNodeId())); }, syncHolder_); - this->DetachFromMe(dep_->GetNodeId()); - this->UnregisterMe(); - } - - virtual UpdateResult Update() override - { - // this->SetCurrentTurn(turn, true); - - // Update of this node could be triggered from deps, - // so make sure source doesnt contain events from last turn - //source_->SetCurrentTurn(turn); - - for (const auto& e : dep_->Events()) - if (apply([this, &e] (const auto& ... syncs) { return this->func_(e, syncs->ValueRef() ...); }, syncHolder_)) - this->Events().push_back(e); - - if (! this->Events().empty()) - return UpdateResult::changed; - else - return UpdateResult::unchanged; - } - - virtual const char* GetNodeType() const override - { return "SyncedEventFilter"; } - - virtual int DependencyCount() const override - { return 1 + sizeof...(TSyncs); } - -private: - std::shared_ptr> dep_; - - F pred_; - - std::tuple>...> syncHolder_; -}; - /////////////////////////////////////////////////////////////////////////////////////////////////// /// EventProcessingNode /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -470,8 +294,8 @@ class EventProcessingNode : public EventStreamNode { public: template - EventProcessingNode(IReactiveGroup* group, const std::shared_ptr>& dep, U&& func) : - EventProcessingNode::EventStreamNode( group ), + EventProcessingNode(const std::shared_ptr& graphPtr, const std::shared_ptr>& dep, U&& func) : + EventProcessingNode::EventStreamNode( graphPtr ), dep_( dep ), func_( std::forward(func) ) { @@ -485,11 +309,11 @@ class EventProcessingNode : public EventStreamNode this->UnregisterMe(); } - virtual UpdateResult Update() override + virtual UpdateResult Update(TurnId turnId) override { - //this->SetCurrentTurn(turn, true); + this->SetCurrentTurn(turnId, true); - func_(EventRange( source_->Events() ), std::back_inserter(this->Events())); + func_(EventRange( dep_->Events() ), std::back_inserter(this->Events())); if (! this->Events().empty()) return UpdateResult::changed; @@ -500,13 +324,13 @@ class EventProcessingNode : public EventStreamNode virtual const char* GetNodeType() const override { return "EventProcessing"; } - virtual int DependencyCount() const override + virtual int GetDependencyCount() const override { return 1; } private: - std::shared_ptr> source_; + std::shared_ptr> dep_; - TFunc func_; + F func_; }; /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -517,11 +341,11 @@ class SyncedEventProcessingNode : public EventStreamNode { public: template - SyncedEventProcessingNode(IReactiveGroup* group, const std::shared_ptr>& dep, U&& func, const std::shared_ptr>& ... syncs) : - SyncedEventProcessingNode::EventStreamNode( group ), + SyncedEventProcessingNode(const std::shared_ptr& graphPtr, const std::shared_ptr>& dep, U&& func, const std::shared_ptr>& ... syncs) : + SyncedEventProcessingNode::EventStreamNode( graphPtr ), dep_( dep ), func_( std::forward(func) ), - syncs_( syncs ... ) + syncHolder_( syncs ... ) { this->RegisterMe(); this->AttachToMe(dep->GetNodeId()); @@ -535,17 +359,17 @@ class SyncedEventProcessingNode : public EventStreamNode this->UnregisterMe(); } - virtual UpdateResult Update() override + virtual UpdateResult Update(TurnId turnId) override { - //this->SetCurrentTurn(turn, true); + this->SetCurrentTurn(turnId, true); // Update of this node could be triggered from deps, // so make sure source doesnt contain events from last turn - //source_->SetCurrentTurn(turn); + source_->SetCurrentTurn(turnId); apply( [this] (const auto& ... syncs) { - func_(EventRange( source_->Events() ), std::back_inserter(this->Events()), syncs->ValueRef() ...); + func_(EventRange( this->dep_->Events() ), std::back_inserter(this->Events()), syncs->Value() ...); }, syncHolder_); @@ -558,7 +382,7 @@ class SyncedEventProcessingNode : public EventStreamNode virtual const char* GetNodeType() const override { return "SycnedEventProcessing"; } - virtual int DependencyCount() const override + virtual int GetDependencyCount() const override { return 1 + sizeof...(TSyncs); } private: @@ -576,8 +400,8 @@ template class EventJoinNode : public EventStreamNode> { public: - EventJoinNode(IReactiveGroup* group, const std::shared_ptr>& ... deps) : - EventJoinNode::EventStreamNode( group ), + EventJoinNode(const std::shared_ptr& graphPtr, const std::shared_ptr>& ... deps) : + EventJoinNode::EventStreamNode( graphPtr ), slots_( deps ... ) { this->RegisterMe(); @@ -590,12 +414,12 @@ class EventJoinNode : public EventStreamNode> this->UnregisterMe(); } - virtual UpdateResult Update() override + virtual UpdateResult Update(TurnId turnId) override { - //this->SetCurrentTurn(turn, true); + this->SetCurrentTurn(turnId, true); // Move events into buffers - apply([this, &turn] (Slot& ... slots) { REACT_EXPAND_PACK(FetchBuffer(turn, slots)); }, slots_); + apply([this, turnId] (Slot& ... slots) { REACT_EXPAND_PACK(FetchBuffer(turnId, slots)); }, slots_); while (true) { @@ -631,7 +455,7 @@ class EventJoinNode : public EventStreamNode> virtual const char* GetNodeType() const override { return "EventJoin"; } - virtual int DependencyCount() const override + virtual int GetDependencyCount() const override { return sizeof...(Ts); } private: @@ -647,9 +471,9 @@ class EventJoinNode : public EventStreamNode> }; template - static void FetchBuffer(TurnT& turn, Slot& slot) + static void FetchBuffer(TurnId turnId, Slot& slot) { - //slot.Source->SetCurrentTurn(turn); + slot.Source->SetCurrentTurn(turnId); slot.buffer.insert(slot.buffer.end(), slot.source->Events().begin(), slot.source->Events().end()); } diff --git a/include/react/detail/graph/GraphBase.h b/include/react/detail/graph/GraphBase.h index 404108d0..43d091da 100644 --- a/include/react/detail/graph/GraphBase.h +++ b/include/react/detail/graph/GraphBase.h @@ -11,76 +11,18 @@ #include "react/detail/Defs.h" +#include #include #include -#include "react/common/Util.h" -#include "react/common/Timing.h" #include "react/common/Types.h" -#include "react/detail/IReactiveGroup.h" -#include "react/detail/IReactiveNode.h" +#include "react/common/Util.h" +#include "react/detail/IReactiveGraph.h" #include "react/detail/ObserverBase.h" /***************************************/ REACT_IMPL_BEGIN /**************************************/ -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// WeightHint -/////////////////////////////////////////////////////////////////////////////////////////////////// -enum class WeightHint -{ - automatic, - light, - heavy -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// UpdateTimingPolicy -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename D, - long long threshold -> -class UpdateTimingPolicy : - private ConditionalTimer -{ - using ScopedTimer = typename UpdateTimingPolicy::ScopedTimer; - -public: - class ScopedUpdateTimer : private ScopedTimer - { - public: - ScopedUpdateTimer(UpdateTimingPolicy& parent, const size_t& count) : - ScopedTimer( parent, count ) - {} - }; - - void ResetUpdateThreshold() { this->Reset(); } - void ForceUpdateThresholdExceeded(bool v) { this->ForceThresholdExceeded(v); } - bool IsUpdateThresholdExceeded() const { return this->IsThresholdExceeded(); } -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// DepCounter -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -struct CountHelper { static const int value = T::dependency_count; }; - -template -struct CountHelper> { static const int value = 1; }; - -template -struct DepCounter; - -template <> -struct DepCounter<0> { static int const value = 0; }; - -template -struct DepCounter -{ - static int const value = - CountHelper::type>::value + DepCounter::value; -}; +struct IReactiveGraph; /////////////////////////////////////////////////////////////////////////////////////////////////// /// NodeBase @@ -88,13 +30,14 @@ struct DepCounter class NodeBase : public IReactiveNode { public: - NodeBase(IReactiveGroup* group) : group_( group ) + NodeBase(const std::shared_ptr& graphPtr) : graphPtr_( graphPtr ) { } + + NodeBase(const NodeBase&) = delete; + NodeBase& operator=(const NodeBase&) = delete; NodeBase(NodeBase&&) = delete; NodeBase& operator=(NodeBase&&) = delete; - NodeBase(const NodeBase&) = delete; - NodeBase& operator=(const NodeBase&) = delete; virtual bool IsInputNode() const override { return false; } @@ -104,11 +47,8 @@ class NodeBase : public IReactiveNode virtual bool IsDynamicNode() const override { return false; } - - virtual bool IsHeavyweight() const override - { return false; } - void SetWeightHint(WeightHint weight) + /*void SetWeightHint(WeightHint weight) { switch (weight) { @@ -122,174 +62,42 @@ class NodeBase : public IReactiveNode this->ResetUpdateThreshold(); break; } - } + }*/ NodeId GetNodeId() const { return nodeId_; } + auto GraphPtr() const -> const std::shared_ptr& + { return graphPtr_; } + + auto GraphPtr() -> std::shared_ptr& + { return graphPtr_; } + protected: void RegisterMe() - { nodeId_ = group_->RegisterNode(); } + { nodeId_ = graphPtr_->RegisterNode(this); } void UnregisterMe() - { group_->UnregisterNode(nodeId_); } + { graphPtr_->UnregisterNode(nodeId_); } void AttachToMe(NodeId otherNodeId) - { group_->OnNodeAttach(nodeId_, otherNodeId); } + { graphPtr_->OnNodeAttach(nodeId_, otherNodeId); } void DetachFromMe(NodeId otherNodeId) - { group_->OnNodeDetach(nodeId_, otherNodeId); } + { graphPtr_->OnNodeDetach(nodeId_, otherNodeId); } void DynamicAttachToMe(NodeId otherNodeId, TurnId turnId) - { group_->OnDynamicNodeAttach(nodeId_, otherNodeId, turnId); } + { graphPtr_->OnDynamicNodeAttach(nodeId_, otherNodeId, turnId); } void DynamicDetachFromMe(NodeId otherNodeId, TurnId turnId) - { group_->OnDynamicNodeDetach(nodeId_, otherNodeId, turnId); } + { graphPtr_->OnDynamicNodeDetach(nodeId_, otherNodeId, turnId); } private: NodeId nodeId_; - IReactiveGroup* group_; -}; -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Attach/detach helper functors -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -struct AttachFunctor -{ - AttachFunctor(TNode& node) : MyNode( node ) {} - - void operator()(const TDeps& ...deps) const - { - REACT_EXPAND_PACK(attach(deps)); - } - - template - void attach(const T& op) const - { - op.template AttachRec(*this); - } - - template - void attach(const std::shared_ptr& depPtr) const - { - D::Engine::OnNodeAttach(MyNode, *depPtr); - } - - TNode& MyNode; + std::shared_ptr graphPtr_; }; -template -struct DetachFunctor -{ - DetachFunctor(TNode& node) : MyNode( node ) {} - - void operator()(const TDeps& ... deps) const - { - REACT_EXPAND_PACK(detach(deps)); - } - - template - void detach(const T& op) const - { - op.template DetachRec(*this); - } - - template - void detach(const std::shared_ptr& depPtr) const - { - D::Engine::OnNodeDetach(MyNode, *depPtr); - } - - TNode& MyNode; -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// ReactiveOpBase -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -class ReactiveOpBase -{ -public: - using DepHolderT = std::tuple; - - template - ReactiveOpBase(DontMove, TDepsIn&& ... deps) : - deps_( std::forward(deps) ... ) - {} - - ReactiveOpBase(ReactiveOpBase&& other) : - deps_( std::move(other.deps_) ) - {} - - // Can't be copied, only moved - ReactiveOpBase(const ReactiveOpBase& other) = delete; - - template - void Attach(TNode& node) const - { - apply(AttachFunctor{ node }, deps_); - } - - template - void Detach(TNode& node) const - { - apply(DetachFunctor{ node }, deps_); - } - - template - void AttachRec(const TFunctor& functor) const - { - // Same memory layout, different func - apply(reinterpret_cast&>(functor), deps_); - } - - template - void DetachRec(const TFunctor& functor) const - { - apply(reinterpret_cast&>(functor), deps_); - } - -public: - static const int dependency_count = DepCounter::value; - -protected: - DepHolderT deps_; -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Iterators for event processing -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -class EventRange -{ -public: - using const_iterator = typename std::vector::const_iterator; - using size_type = typename std::vector::size_type; - - // Copy ctor - EventRange(const EventRange&) = default; - - // Copy assignment - EventRange& operator=(const EventRange&) = default; - - const_iterator begin() const { return data_.begin(); } - const_iterator end() const { return data_.end(); } - - size_type Size() const { return data_.size(); } - bool IsEmpty() const { return data_.empty(); } - - explicit EventRange(const std::vector& data) : - data_( data ) - {} - -private: - const std::vector& data_; -}; - -template -using EventEmitter = std::back_insert_iterator>; - /****************************************/ REACT_IMPL_END /***************************************/ #endif // REACT_DETAIL_GRAPH_GRAPHBASE_H_INCLUDED \ No newline at end of file diff --git a/include/react/detail/graph/ObserverNodes.h b/include/react/detail/graph/ObserverNodes.h index b597e828..b90e118e 100644 --- a/include/react/detail/graph/ObserverNodes.h +++ b/include/react/detail/graph/ObserverNodes.h @@ -23,337 +23,167 @@ /////////////////////////////////////////////////////////////////////////////////////////////////// /// Forward declarations /////////////////////////////////////////////////////////////////////////////////////////////////// -template +template class SignalNode; -template +template class EventStreamNode; -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// ObserverAction -/////////////////////////////////////////////////////////////////////////////////////////////////// -enum class ObserverAction -{ - next, - stop_and_detach -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// AddObserverRangeWrapper -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -struct AddObserverRangeWrapper -{ - AddObserverRangeWrapper(const AddObserverRangeWrapper& other) = default; - - AddObserverRangeWrapper(AddObserverRangeWrapper&& other) : - MyFunc( std::move(other.MyFunc) ) - {} - - template - < - typename FIn, - class = typename DisableIfSame::type - > - explicit AddObserverRangeWrapper(FIn&& func) : - MyFunc( std::forward(func) ) - {} - - ObserverAction operator()(EventRange range, const TArgs& ... args) - { - for (const auto& e : range) - if (MyFunc(e, args ...) == ObserverAction::stop_and_detach) - return ObserverAction::stop_and_detach; - - return ObserverAction::next; - } - - F MyFunc; -}; - /////////////////////////////////////////////////////////////////////////////////////////////////// /// ObserverNode /////////////////////////////////////////////////////////////////////////////////////////////////// -template -class ObserverNode : - public NodeBase, - public IObserver +class ObserverNode : public NodeBase, public IObserver { public: - ObserverNode() = default; + ObserverNode(IReactiveGraph* group) : NodeBase( group ) + { } + + ObserverNode(ObserverNode&&) = default; + ObserverNode& operator=(ObserverNode&&) = default; - virtual bool IsOutputNode() const { return true; } + ObserverNode(const ObserverNode&) = delete; + ObserverNode& operator=(const ObserverNode&) = delete; + + virtual bool IsOutputNode() const + { return true; } }; /////////////////////////////////////////////////////////////////////////////////////////////////// /// SignalObserverNode /////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename D, - typename S, - typename TFunc -> -class SignalObserverNode : - public ObserverNode +template +class SignalObserverNode : public ObserverNode { - using Engine = typename SignalObserverNode::Engine; - public: - template - SignalObserverNode(const std::shared_ptr>& subject, F&& func) : - SignalObserverNode::ObserverNode( ), + template + SignalObserverNode(IReactiveGraph* group, const std::shared_ptr>& subject, FIn&& func) : + SignalObserverNode::ObserverNode( group ), subject_( subject ), - func_( std::forward(func) ) + func_( std::forward(func) ) { - Engine::OnNodeCreate(*this); - Engine::OnNodeAttach(*this, *subject); + this->RegisterMe(); + this->AttachToMe(subject->GetNodeId()); } ~SignalObserverNode() { - Engine::OnNodeDestroy(*this); + this->DetachFromMe(subject->GetNodeId()); + this->UnregisterMe(); } - virtual const char* GetNodeType() const override { return "SignalObserverNode"; } - virtual int DependencyCount() const override { return 1; } - - virtual void Update(void* turnPtr) override - { -#ifdef REACT_ENABLE_LOGGING - using TurnT = typename D::Engine::TurnT; - TurnT& turn = *reinterpret_cast(turnPtr); -#endif - - REACT_LOG(D::Log().template Append( - GetObjectId(*this), turn.Id())); + virtual const char* GetNodeType() const override + { return "SignalObserver"; } - bool shouldDetach = false; + virtual int DependencyCount() const override + { return 1; } - if (auto p = subject_.lock()) - {// timer - using TimerT = typename SignalObserverNode::ScopedUpdateTimer; - TimerT scopedTimer( *this, 1 ); - - if (func_(p->ValueRef()) == ObserverAction::stop_and_detach) - shouldDetach = true; - }// ~timer - - if (shouldDetach) - DomainSpecificInputManager::Instance() - .QueueObserverForDetach(*this); - - REACT_LOG(D::Log().template Append( - GetObjectId(*this), turn.Id())); - } - - virtual void UnregisterSelf() override + virtual UpdateResult Update(TurnId turnId) override { - if (auto p = subject_.lock()) - p->UnregisterObserver(this); + func_(subject_->Value()); + return UpdateResult::unchanged; } private: - virtual void detachObserver() override - { - if (auto p = subject_.lock()) - { - Engine::OnNodeDetach(*this, *p); - subject_.reset(); - } - } + std::shared_ptr> subject_; - std::weak_ptr> subject_; - TFunc func_; + F func_; }; /////////////////////////////////////////////////////////////////////////////////////////////////// /// EventObserverNode /////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename D, - typename E, - typename TFunc -> -class EventObserverNode : - public ObserverNode +template +class EventObserverNode : public ObserverNode { - using Engine = typename EventObserverNode::Engine; - public: - template - EventObserverNode(const std::shared_ptr>& subject, F&& func) : - EventObserverNode::ObserverNode( ), + template + EventObserverNode(IReactiveGraph* group, const std::shared_ptr>& subject, FIn&& func) : + EventObserverNode::ObserverNode( group ), subject_( subject ), - func_( std::forward(func) ) + func_( std::forward(func) ) { - Engine::OnNodeCreate(*this); - Engine::OnNodeAttach(*this, *subject); + this->RegisterMe(); + this->AttachToMe(subject->GetNodeId()); } ~EventObserverNode() { - Engine::OnNodeDestroy(*this); + this->DetachFromMe(subject->GetNodeId()); + this->UnregisterMe(); } - virtual const char* GetNodeType() const override { return "EventObserverNode"; } - virtual int DependencyCount() const override { return 1; } - - virtual void Update(void* turnPtr) override - { -#ifdef REACT_ENABLE_LOGGING - using TurnT = typename D::Engine::TurnT; - TurnT& turn = *reinterpret_cast(turnPtr); -#endif - - REACT_LOG(D::Log().template Append( - GetObjectId(*this), turn.Id())); - - bool shouldDetach = false; - - if (auto p = subject_.lock()) - {// timer - using TimerT = typename EventObserverNode::ScopedUpdateTimer; - TimerT scopedTimer( *this, p->Events().size() ); + virtual const char* GetNodeType() const override + { return "EventObserverNode"; } - shouldDetach = func_(EventRange( p->Events() )) == ObserverAction::stop_and_detach; + virtual int DependencyCount() const override + { return 1; } - }// ~timer - - if (shouldDetach) - DomainSpecificInputManager::Instance() - .QueueObserverForDetach(*this); - - REACT_LOG(D::Log().template Append( - GetObjectId(*this), turn.Id())); - } - - virtual void UnregisterSelf() override + virtual UpdateResult Update(TurnId turnId) override { - if (auto p = subject_.lock()) - p->UnregisterObserver(this); + func_(EventRange( subject_->Events() )); + return UpdateResult::unchanged; } private: - std::weak_ptr> subject_; - - TFunc func_; + std::shared_ptr> subject_; - virtual void detachObserver() - { - if (auto p = subject_.lock()) - { - Engine::OnNodeDetach(*this, *p); - subject_.reset(); - } - } + F func_; }; /////////////////////////////////////////////////////////////////////////////////////////////////// /// SyncedObserverNode /////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename D, - typename E, - typename TFunc, - typename ... TDepValues -> -class SyncedObserverNode : - public ObserverNode +template +class SyncedObserverNode : public ObserverNode { - using Engine = typename SyncedObserverNode::Engine; - public: - template - SyncedObserverNode(const std::shared_ptr>& subject, F&& func, - const std::shared_ptr>& ... deps) : - SyncedObserverNode::ObserverNode( ), + template + SyncedObserverNode(IReactiveGraph* group, const std::shared_ptr>& subject, FIn&& func, const std::shared_ptr>& ... syncs) : + SyncedObserverNode::ObserverNode( group ), subject_( subject ), - func_( std::forward(func) ), - deps_( deps ... ) + func_( std::forward(func) ), + syncHolder_( syncs ... ) { - Engine::OnNodeCreate(*this); - Engine::OnNodeAttach(*this, *subject); - - REACT_EXPAND_PACK(Engine::OnNodeAttach(*this, *deps)); + this->RegisterMe(); + this->AttachToMe(subject->GetNodeId()); + REACT_EXPAND_PACK(this->AttachToMe(syncs->GetNodeId())); } ~SyncedObserverNode() { - Engine::OnNodeDestroy(*this); + apply([this] (const auto& ... syncs) { REACT_EXPAND_PACK(this->DetachFromMe(syncs->GetNodeId())); }, syncHolder_); + this->DetachFromMe(subject_->GetNodeId()); + this->UnregisterMe(); } - virtual const char* GetNodeType() const override { return "SyncedObserverNode"; } - virtual int DependencyCount() const override { return 1 + sizeof...(TDepValues); } + virtual const char* GetNodeType() const override + { return "SyncedObserverNode"; } - virtual void Update(void* turnPtr) override - { - using TurnT = typename D::Engine::TurnT; - TurnT& turn = *reinterpret_cast(turnPtr); - - REACT_LOG(D::Log().template Append( - GetObjectId(*this), turn.Id())); - - bool shouldDetach = false; - - if (auto p = subject_.lock()) - { - // Update of this node could be triggered from deps, - // so make sure source doesnt contain events from last turn - p->SetCurrentTurn(turn); - - {// timer - using TimerT = typename SyncedObserverNode::ScopedUpdateTimer; - TimerT scopedTimer( *this, p->Events().size() ); + virtual int DependencyCount() const override + { return 1 + sizeof...(TSyncs); } + + virtual UpdateResult Update(TurnId turnId) override + { + // Update of this node could be triggered from deps, + // so make sure source doesnt contain events from last turn + p->SetCurrentTurn(turnId); - shouldDetach = apply( - [this, &p] (const std::shared_ptr>& ... args) - { - return func_(EventRange( p->Events() ), args->ValueRef() ...); - }, - deps_) == ObserverAction::stop_and_detach; - - }// ~timer - } - - if (shouldDetach) - DomainSpecificInputManager::Instance() - .QueueObserverForDetach(*this); - - REACT_LOG(D::Log().template Append( - GetObjectId(*this), turn.Id())); - } + shouldDetach = apply( + [this] (const auto& ... syncs) + { + func_(EventRange( this->subject_->Events() ), syncs->Value() ...); + }, + syncHolder_); - virtual void UnregisterSelf() override - { - if (auto p = subject_.lock()) - p->UnregisterObserver(this); + return UpdateResult::unchanged; } private: - using DepHolderT = std::tuple>...>; - - std::weak_ptr> subject_; + std::shared_ptr> subject_; - TFunc func_; - DepHolderT deps_; - - virtual void detachObserver() - { - if (auto p = subject_.lock()) - { - Engine::OnNodeDetach(*this, *p); - - apply( - DetachFunctor>...>( *this ), - deps_); + F func_; - subject_.reset(); - } - } + std::tuple>...> syncHolder_; }; /****************************************/ REACT_IMPL_END /***************************************/ diff --git a/include/react/detail/graph/PropagationMT.h b/include/react/detail/graph/PropagationMT.h new file mode 100644 index 00000000..e69de29b diff --git a/include/react/detail/graph/PropagationST.h b/include/react/detail/graph/PropagationST.h new file mode 100644 index 00000000..bfbc0828 --- /dev/null +++ b/include/react/detail/graph/PropagationST.h @@ -0,0 +1,284 @@ + +// Copyright Sebastian Jeckel 2016. +// 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) + +#ifndef REACT_DETAIL_GRAPH_PROPAGATIONST_H_INCLUDED +#define REACT_DETAIL_GRAPH_PROPAGATIONST_H_INCLUDED + +#pragma once + +#include "react/detail/Defs.h" + +#include +#include +#include +#include + +#include "react/common/Containers.h" +#include "react/common/Types.h" +#include "react/detail/IReactiveGraph.h" + +/***************************************/ REACT_IMPL_BEGIN /**************************************/ + +class SingleThreadedGraph : public IReactiveGraph +{ +public: + // IReactiveGraph + virtual NodeId RegisterNode(IReactiveNode* nodePtr) override; + virtual void UnregisterNode(NodeId node) override; + + virtual void OnNodeAttach(NodeId node, NodeId parentId) override; + virtual void OnNodeDetach(NodeId node, NodeId parentId) override; + + virtual void OnDynamicNodeAttach(NodeId node, NodeId parentId, TurnId turnId) override; + virtual void OnDynamicNodeDetach(NodeId node, NodeId parentId, TurnId turnId) override; + + virtual void AddInput(NodeId nodeId, std::function inputCallback) override; + // ~IReactiveGraph + + template + void DoTransaction(TransactionFlags flags, F&& transactionCallback); + +private: + struct NodeData + { + NodeData() = default; + + NodeData(const NodeData&) = default; + NodeData& operator=(const NodeData&) = default; + + NodeData(IReactiveNode* nodePtrIn) : + nodePtr( nodePtrIn ) + { } + + int level = 0; + int newLevel = 0 ; + bool queued = false; + + IReactiveNode* nodePtr = nullptr; + + std::vector successors; + }; + + class TopoQueue + { + public: + void Push(NodeId nodeId, int level) + { queueData_.emplace_back(nodeId, level); } + + bool FetchNext(); + + const std::vector& Next() const + { return nextData_; } + + bool IsEmpty() const + { return queueData_.empty(); } + + private: + using Entry = std::pair; + + std::vector queueData_; + std::vector nextData_; + + int minLevel_ = (std::numeric_limits::max)(); + }; + + void Propagate(); + + void ScheduleSuccessors(NodeData & node); + void InvalidateSuccessors(NodeData & node); + +private: + int refCount_ = 1; + + TopoQueue scheduledNodes_; + IndexMap nodeData_; + std::vector changedInputs_; + + bool isTransactionActive_ = false; +}; + +NodeId SingleThreadedGraph::RegisterNode(IReactiveNode* nodePtr) +{ + return nodeData_.Insert(NodeData{ nodePtr }); +} + +void SingleThreadedGraph::UnregisterNode(NodeId nodeId) +{ + nodeData_.Remove(nodeId); + +} + +void SingleThreadedGraph::OnNodeAttach(NodeId nodeId, NodeId parentId) +{ + auto& node = nodeData_[nodeId]; + auto& parent = nodeData_[parentId]; + + parent.successors.push_back(nodeId); + + if (node.level <= parent.level) + node.level = parent.level + 1; +} + +void SingleThreadedGraph::OnNodeDetach(NodeId nodeId, NodeId parentId) +{ + auto& parent = nodeData_[parentId]; + auto& successors = parent.successors; + + successors.erase(std::find(successors.begin(), successors.end(), nodeId)); +} + +void SingleThreadedGraph::OnDynamicNodeAttach(NodeId nodeId, NodeId parentId, TurnId turnId) +{ + OnNodeAttach(nodeId, parentId); +} + +void SingleThreadedGraph::OnDynamicNodeDetach(NodeId nodeId, NodeId parentId, TurnId turnId) +{ + OnNodeDetach(nodeId, parentId); +} + +void SingleThreadedGraph::AddInput(NodeId nodeId, std::function inputCallback) +{ + auto& node = nodeData_[nodeId]; + auto* nodePtr = node.nodePtr; + + // This write to the input buffer of the respective node. + inputCallback(); + + if (isTransactionActive_) + { + // If a transaction is active, don't propagate immediately. + // Instead, record the node and wait for more inputs. + changedInputs_.push_back(nodeId); + } + else + { + // Update the node. This applies the input buffer to the node value and checks if it changed. + if (nodePtr->Update(0) == UpdateResult::changed) + { + // Propagate changes through the graph + ScheduleSuccessors(node); + + if (! scheduledNodes_.IsEmpty()) + Propagate(); + } + } +} + +template +void SingleThreadedGraph::DoTransaction(TransactionFlags flags, F&& transactionCallback) +{ + // Transaction callback may add multiple inputs. + isTransactionActive_ = true; + std::forward(transactionCallback)(); + isTransactionActive_ = false; + + // Apply all buffered inputs. + for (NodeId nodeId : changedInputs_) + { + auto& node = nodeData_[nodeId]; + + if (node.nodePtr->Update(0) == UpdateResult::changed) + ScheduleSuccessors(node); + } + + changedInputs_.clear(); + + // Propagate changes through the graph. + if (! scheduledNodes_.IsEmpty()) + Propagate(); +} + +void SingleThreadedGraph::Propagate() +{ + while (scheduledNodes_.FetchNext()) + { + for (NodeId nodeId : scheduledNodes_.Next()) + { + auto& node = nodeData_[nodeId]; + + if (node.level < node.newLevel) + { + // Re-schedule this node + node.level = node.newLevel; + InvalidateSuccessors(node); + scheduledNodes_.Push(nodeId, node.level); + continue; + } + + auto result = node.nodePtr->Update(0); + + if (result == UpdateResult::changed) + { + ScheduleSuccessors(node); + } + else if (result == UpdateResult::shifted) + { + // Re-schedule this node + InvalidateSuccessors(node); + scheduledNodes_.Push(nodeId, node.level); + continue; + } + + node.queued = false; + } + } +} + +void SingleThreadedGraph::ScheduleSuccessors(NodeData& node) +{ + for (NodeId succId : node.successors) + { + auto& succ = nodeData_[succId]; + + if (!succ.queued) + { + succ.queued = true; + scheduledNodes_.Push(succId, succ.level); + } + } +} + +void SingleThreadedGraph::InvalidateSuccessors(NodeData& node) +{ + for (NodeId succId : node.successors) + { + auto& succ = nodeData_[succId]; + + if (succ.newLevel <= node.level) + succ.newLevel = node.level + 1; + } +} + +bool SingleThreadedGraph::TopoQueue::FetchNext() +{ + // Throw away previous values + nextData_.clear(); + + // Find min level of nodes in queue data + minLevel_ = (std::numeric_limits::max)(); + for (const auto& e : queueData_) + if (minLevel_ > e.second) + minLevel_ = e.second; + + // Swap entries with min level to the end + auto p = std::partition(queueData_.begin(), queueData_.end(), [t = minLevel_] (const Entry& e) { return t != e.second; }); + + // Move min level values to next data + nextData_.reserve(std::distance(p, queueData_.end())); + + for (auto it = p; it != queueData_.end(); ++it) + nextData_.push_back(it->first); + + // Truncate moved entries + queueData_.resize(std::distance(queueData_.begin(), p)); + + return !nextData_.empty(); +} + +/****************************************/ REACT_IMPL_END /***************************************/ + +#endif // REACT_DETAIL_GRAPH_PROPAGATIONST_H_INCLUDED \ No newline at end of file diff --git a/include/react/detail/graph/ReactorNodes.h b/include/react/detail/graph/ReactorNodes.h deleted file mode 100644 index c85cdcc0..00000000 --- a/include/react/detail/graph/ReactorNodes.h +++ /dev/null @@ -1,259 +0,0 @@ - -// Copyright Sebastian Jeckel 2016. -// 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) - -#ifndef REACT_DETAIL_GRAPH_REACTORNODES_H_INCLUDED -#define REACT_DETAIL_GRAPH_REACTORNODES_H_INCLUDED - -#pragma once - -#include "react/detail/Defs.h" - -#include -#include -#include -#include -#include - -#include - -#include "GraphBase.h" -#include "EventNodes.h" -#include "SignalNodes.h" - -/***************************************/ REACT_IMPL_BEGIN /**************************************/ - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// ReactorNode -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename D, - typename TContext -> -class ReactorNode : - public NodeBase -{ - using Engine = typename ReactorNode::Engine; - -public: - using CoroutineT = boost::coroutines::coroutine*>; - using PullT = typename CoroutineT::pull_type; - using PushT = typename CoroutineT::push_type; - using TurnT = typename D::Engine::TurnT; - - template - ReactorNode(F&& func) : - ReactorNode::NodeBase( ), - func_( std::forward(func) ) - { - Engine::OnNodeCreate(*this); - } - - ~ReactorNode() - { - Engine::OnNodeDestroy(*this); - } - - void StartLoop() - { - mainLoop_ = PullT - ( - [&] (PushT& out) - { - curOutPtr_ = &out; - - TContext ctx( *this ); - - // Start the loop function. - // It will reach it its first Await at some point. - while (true) - { - func_(ctx); - } - } - ); - - // First blocking event is not initiated by Tick() but after loop creation. - NodeBase* p = mainLoop_.get(); - doAttach(p); - - ++depCount_; - } - - virtual const char* GetNodeType() const override { return "ReactorNode"; } - - virtual bool IsDynamicNode() const override { return true; } - virtual bool IsOutputNode() const override { return true; } - - virtual void Update(void* turnPtr) override - { - turnPtr_ = reinterpret_cast(turnPtr); - - mainLoop_(); - - NodeBase* p = mainLoop_.get(); - - if (p != nullptr) - { - doDynAttach(p); - } - else - { - offsets_.clear(); - } - - turnPtr_ = nullptr; - } - - virtual int DependencyCount() const override - { - return depCount_; - } - - template - E& Await(const std::shared_ptr>& events) - { - // First attach to target event node - (*curOutPtr_)(events.get()); - - while (! checkEvent(events)) - (*curOutPtr_)(nullptr); - - doDynDetach(events.get()); - - auto index = offsets_[reinterpret_cast(events.get())]++; - return events->Events()[index]; - } - - template - void RepeatUntil(const std::shared_ptr>& eventsPtr, const F& func) - { - // First attach to target event node - if (turnPtr_ != nullptr) - { - (*curOutPtr_)(eventsPtr.get()); - } - else - { - // Non-dynamic attach in case first loop until is encountered before the loop was - // suspended for the first time. - doAttach(eventsPtr.get()); - } - - // Don't enter loop if event already present - if (! checkEvent(eventsPtr)) - { - auto* parentOutPtr = curOutPtr_; - - // Create and start loop - PullT nestedLoop_ - { - [&] (PushT& out) - { - curOutPtr_ = &out; - while (true) - func(); - } - }; - - // First suspend from initial loop run - (*parentOutPtr)(nestedLoop_.get()); - - // Further iterations - while (! checkEvent(eventsPtr)) - { - // Advance loop, forward blocking event to parent, and suspend - nestedLoop_(); - (*parentOutPtr)(nestedLoop_.get()); - } - - curOutPtr_ = parentOutPtr; - } - - // Detach when this function is exited - if (turnPtr_ != nullptr) - Engine::OnDynamicNodeDetach(*this, *eventsPtr, *turnPtr_); - else - Engine::OnNodeDetach(*this, *eventsPtr); - - --depCount_; - } - - template - const S& Get(const std::shared_ptr>& sigPtr) - { - // Do dynamic attach followed by attach if Get() happens during a turn. - if (turnPtr_ != nullptr) - { - // Request attach - (*curOutPtr_)(sigPtr.get()); - - doDynDetach(sigPtr.get()); - } - - return sigPtr->ValueRef(); - } - -private: - template - bool checkEvent(const std::shared_ptr>& events) - { - if (turnPtr_ == nullptr) - return false; - - events->SetCurrentTurn(*turnPtr_); - - auto index = reinterpret_cast(events.get()); - return offsets_[index] < events->Events().size(); - } - - void doAttach(NodeBase* nodePtr) - { - assert(nodePtr != nullptr); - assert(turnPtr_ == nullptr); - Engine::OnNodeAttach(*this, *nodePtr); - ++depCount_; - } - - void doDetach(NodeBase* nodePtr) - { - assert(nodePtr != nullptr); - assert(turnPtr_ == nullptr); - Engine::OnNodeDetach(*this, *nodePtr); - --depCount_; - } - - void doDynAttach(NodeBase* nodePtr) - { - assert(nodePtr != nullptr); - assert(turnPtr_ != nullptr); - Engine::OnDynamicNodeAttach(*this, *nodePtr, *turnPtr_); - ++depCount_; - } - - void doDynDetach(NodeBase* nodePtr) - { - assert(nodePtr != nullptr); - assert(turnPtr_ != nullptr); - Engine::OnDynamicNodeDetach(*this, *nodePtr, *turnPtr_); - --depCount_; - } - - std::function func_; - - PullT mainLoop_; - TurnT* turnPtr_; - - PushT* curOutPtr_ = nullptr; - - uint depCount_ = 0; - - std::unordered_map offsets_; -}; - -/****************************************/ REACT_IMPL_END /***************************************/ - -#endif // REACT_DETAIL_GRAPH_REACTORNODES_H_INCLUDED \ No newline at end of file diff --git a/include/react/detail/graph/SignalNodes.h b/include/react/detail/graph/SignalNodes.h index 8f9424dc..b926ffa1 100644 --- a/include/react/detail/graph/SignalNodes.h +++ b/include/react/detail/graph/SignalNodes.h @@ -28,307 +28,202 @@ bool Equals(const L& lhs, const R& rhs); /// SignalNode /////////////////////////////////////////////////////////////////////////////////////////////////// template -class SignalNode : public ObservableNode +class SignalNode : public NodeBase { public: - SignalNode() = default; + SignalNode(SignalNode&&) = default; + SignalNode& operator=(SignalNode&&) = default; + + SignalNode(const SignalNode&) = delete; + SignalNode& operator=(const SignalNode&) = delete; template - explicit SignalNode(U&& value) : - SignalNode::ObservableNode( ), + SignalNode(const std::shared_ptr& graphPtr, U&& value) : + SignalNode::NodeBase( graphPtr ), value_( std::forward(value) ) - {} + { } - const S& ValueRef() const - { - return value_; - } + T& Value() + { return value_; } -protected: - S value_; -}; + const T& Value() const + { return value_; } -template -using SignalNodePtrT = std::shared_ptr>; +private: + T value_; +}; /////////////////////////////////////////////////////////////////////////////////////////////////// /// VarNode /////////////////////////////////////////////////////////////////////////////////////////////////// -template -class VarNode : - public SignalNode, - public IInputNode +template +class VarSignalNode : public SignalNode { - using Engine = typename VarNode::Engine; - public: template - VarNode(T&& value) : - VarNode::SignalNode( std::forward(value) ), + VarSignalNode(const std::shared_ptr& graphPtr, T&& value) : + VarSignalNode::SignalNode( graphPtr, std::forward(value) ), newValue_( value ) - { - Engine::OnNodeCreate(*this); - } + { this->RegisterMe(); } - ~VarNode() - { - Engine::OnNodeDestroy(*this); - } + ~VarSignalNode() + { this->UnregisterMe(); } - virtual const char* GetNodeType() const override { return "VarNode"; } - virtual bool IsInputNode() const override { return true; } - virtual int DependencyCount() const override { return 0; } + virtual const char* GetNodeType() const override + { return "VarSignal"; } - virtual void Update(void* turnPtr) override - { - REACT_ASSERT(false, "Ticked VarNode\n"); - } - - template - void AddInput(V&& newValue) - { - newValue_ = std::forward(newValue); + virtual bool IsInputNode() const override + { return true; } - isInputAdded_ = true; - - // isInputAdded_ takes precedences over isInputModified_ - // the only difference between the two is that isInputModified_ doesn't/can't compare - isInputModified_ = false; - } + virtual int GetDependencyCount() const override + { return 0; } - // This is signal-specific - template - void ModifyInput(F& func) + virtual UpdateResult Update(TurnId turnId) override { - // There hasn't been any Set(...) input yet, modify. - if (! isInputAdded_) - { - func(this->value_); - - isInputModified_ = true; - } - // There's a newValue, modify newValue instead. - // The modified newValue will handled like before, i.e. it'll be compared to value_ - // in ApplyInput - else - { - func(newValue_); - } - } - - virtual bool ApplyInput(void* turnPtr) override - { - using TurnT = typename D::Engine::TurnT; - TurnT& turn = *reinterpret_cast(turnPtr); - if (isInputAdded_) { isInputAdded_ = false; - if (! Equals(this->value_, newValue_)) + if (! Equals(this->Value(), newValue_)) { - this->value_ = std::move(newValue_); - Engine::OnInputChange(*this, turn); - return true; + this->Value() = std::move(newValue_); + return UpdateResult::changed; } else { - return false; + return UpdateResult::unchanged; } } else if (isInputModified_) { isInputModified_ = false; - - Engine::OnInputChange(*this, turn); - return true; + return UpdateResult::changed; } else { - return false; + return UpdateResult::unchanged; } } -private: - S newValue_; - bool isInputAdded_ = false; - bool isInputModified_ = false; -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// FunctionOp -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename S, - typename F, - typename ... TDeps -> -class FunctionOp : public ReactiveOpBase -{ -public: - template - FunctionOp(FIn&& func, TDepsIn&& ... deps) : - FunctionOp::ReactiveOpBase( DontMove(), std::forward(deps) ... ), - func_( std::forward(func) ) - {} - - FunctionOp(FunctionOp&& other) : - FunctionOp::ReactiveOpBase( std::move(other) ), - func_( std::move(other.func_) ) - {} - - S Evaluate() + template + void SetValue(U&& newValue) { - return apply(EvalFunctor( func_ ), this->deps_); + newValue_ = std::forward(newValue); + + isInputAdded_ = true; + + // isInputAdded_ takes precedences over isInputModified_ + // the only difference between the two is that isInputModified_ doesn't/can't compare + isInputModified_ = false; } -private: - // Eval - struct EvalFunctor + // This is signal-specific + template + void ModifyValue(F&& func) { - EvalFunctor(F& f) : MyFunc( f ) {} - - template - S operator()(T&& ... args) + // There hasn't been any Set(...) input yet, modify. + if (! isInputAdded_) { - return MyFunc(eval(args) ...); - } + func(this->Value()); - template - static auto eval(T& op) -> decltype(op.Evaluate()) - { - return op.Evaluate(); + isInputModified_ = true; } - - template - static auto eval(const std::shared_ptr& depPtr) -> decltype(depPtr->ValueRef()) + // There's a newValue, modify newValue instead. + // The modified newValue will handled like before, i.e. it'll be compared to value_ + // in ApplyInput + else { - return depPtr->ValueRef(); + func(newValue_); } - - F& MyFunc; - }; + } private: - F func_; + T newValue_; + bool isInputAdded_ = false; + bool isInputModified_ = false; }; /////////////////////////////////////////////////////////////////////////////////////////////////// /// SignalOpNode /////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename S, - typename TOp -> -class SignalOpNode : public SignalNode +template +class SignalFuncNode : public SignalNode { - using Engine = typename SignalOpNode::Engine; - public: - template - SignalOpNode(TArgs&& ... args) : - SignalOpNode::SignalNode( ), - op_( std::forward(args) ... ) + template + SignalFuncNode(const std::shared_ptr& graphPtr, U&& func, const std::shared_ptr>& ... deps) : + SignalFuncNode::SignalNode( graphPtr, func(deps->Value() ...) ), + func_( std::forward(func) ), + depHolder_( deps ... ) { - this->value_ = op_.Evaluate(); - - Engine::OnNodeCreate(*this); - op_.template Attach(*this); + this->RegisterMe(); + REACT_EXPAND_PACK(this->AttachToMe(deps->GetNodeId())); } - ~SignalOpNode() + ~SignalFuncNode() { - if (!wasOpStolen_) - op_.template Detach(*this); - Engine::OnNodeDestroy(*this); + apply([this] (const auto& ... deps) { REACT_EXPAND_PACK(this->DetachFromMe(deps->GetNodeId())); }, depHolder_); + this->UnregisterMe(); } - virtual void Update(void* turnPtr) override - { - using TurnT = typename D::Engine::TurnT; - TurnT& turn = *reinterpret_cast(turnPtr); - - REACT_LOG(D::Log().template Append(GetObjectId(*this), turn.Id())); - + virtual UpdateResult Update(TurnId turnId) override + { bool changed = false; - {// timer - using TimerT = typename SignalOpNode::ScopedUpdateTimer; - TimerT scopedTimer( *this, 1 ); - - S newValue = op_.Evaluate(); - - if (! Equals(this->value_, newValue)) - { - this->value_ = std::move(newValue); - changed = true; - } - }// ~timer + T newValue = apply([this] (const auto& ... deps) { return this->func_(deps->Value() ...); }, depHolder_); - REACT_LOG(D::Log().template Append(GetObjectId(*this), turn.Id())); + if (! Equals(this->Value(), newValue)) + { + this->Value() = std::move(newValue); + changed = true; + } if (changed) - Engine::OnNodePulse(*this, turn); + return UpdateResult::changed; else - Engine::OnNodeIdlePulse(*this, turn); + return UpdateResult::unchanged; } - virtual const char* GetNodeType() const override { return "SignalOpNode"; } - virtual int DependencyCount() const override { return TOp::dependency_count; } + virtual const char* GetNodeType() const override + { return "SignalFunc"; } - TOp StealOp() - { - REACT_ASSERT(wasOpStolen_ == false, "Op was already stolen."); - wasOpStolen_ = true; - op_.template Detach(*this); - return std::move(op_); - } + virtual int GetDependencyCount() const override + { return sizeof...(TDeps); } private: - TOp op_; - bool wasOpStolen_ = false; + std::tuple> ...> depHolder_; + + F func_; }; /////////////////////////////////////////////////////////////////////////////////////////////////// /// FlattenNode /////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename TOuter, - typename TInner -> -class FlattenNode : public SignalNode +template +class SignalFlattenNode : public SignalNode { - using Engine = typename FlattenNode::Engine; - public: - FlattenNode(const std::shared_ptr>& outer, - const std::shared_ptr>& inner) : - FlattenNode::SignalNode( inner->ValueRef() ), + SignalFlattenNode(const std::shared_ptr& graphPtr, const std::shared_ptr>& outer, const std::shared_ptr>& inner) : + SignalFlattenNode::SignalNode( graphPtr, inner->Value() ), outer_( outer ), inner_( inner ) { - Engine::OnNodeCreate(*this); - Engine::OnNodeAttach(*this, *outer_); - Engine::OnNodeAttach(*this, *inner_); + this->RegisterMe(); + this->AttachToMe(outer->GetNodeId()); + this->AttachToMe(inner->GetNodeId()); } - ~FlattenNode() + ~SignalFlattenNode() { - Engine::OnNodeDetach(*this, *inner_); - Engine::OnNodeDetach(*this, *outer_); - Engine::OnNodeDestroy(*this); + this->DetachFromMe(inner->GetNodeId()); + this->DetachFromMe(outer->GetNodeId()); + this->UnregisterMe(); } - virtual void Update(void* turnPtr) override + virtual UpdateResult Update(TurnId turnId) override { - using TurnT = typename D::Engine::TurnT; - TurnT& turn = *reinterpret_cast(turnPtr); - - auto newInner = GetNodePtr(outer_->ValueRef()); + auto newInner = GetNodePtr(outer_->Value()); if (newInner != inner_) { @@ -336,36 +231,35 @@ class FlattenNode : public SignalNode auto oldInner = inner_; inner_ = newInner; - Engine::OnDynamicNodeDetach(*this, *oldInner, turn); - Engine::OnDynamicNodeAttach(*this, *newInner, turn); + this->DynamicDetachFromMe(oldInner->GetNodeId(), 0); + this->DynamicAttachToMe(newInner->GetNodeId(), 0); - return; + return UpdateResult::shifted; } - REACT_LOG(D::Log().template Append( - GetObjectId(*this), turn.Id())); - - REACT_LOG(D::Log().template Append( - GetObjectId(*this), turn.Id())); - - if (! Equals(this->value_, inner_->ValueRef())) + if (! Equals(this->Value(), inner_->Value())) { - this->value_ = inner_->ValueRef(); - Engine::OnNodePulse(*this, turn); + this->Value() = inner_->Value(); + return UpdateResult::changed; } else { - Engine::OnNodeIdlePulse(*this, turn); + return UpdateResult::unchanged; } } - virtual const char* GetNodeType() const override { return "FlattenNode"; } - virtual bool IsDynamicNode() const override { return true; } - virtual int DependencyCount() const override { return 2; } + virtual const char* GetNodeType() const override + { return "SignalFlatten"; } + + virtual bool IsDynamicNode() const override + { return true; } + + virtual int GetDependencyCount() const override + { return 2; } private: - std::shared_ptr> outer_; - std::shared_ptr> inner_; + std::shared_ptr> outer_; + std::shared_ptr> inner_; }; /****************************************/ REACT_IMPL_END /***************************************/ diff --git a/include/react/engine/PulsecountEngine.h b/include/react/engine/PulsecountEngine.h index 95308f3c..78999c6f 100644 --- a/include/react/engine/PulsecountEngine.h +++ b/include/react/engine/PulsecountEngine.h @@ -9,6 +9,8 @@ #pragma once +#if 0 + #include "react/detail/Defs.h" #include @@ -144,4 +146,6 @@ struct NodeUpdateTimerEnabled> : std::tru /****************************************/ REACT_IMPL_END /***************************************/ -#endif // REACT_DETAIL_ENGINE_PULSECOUNTENGINE_H_INCLUDED \ No newline at end of file +#endif // REACT_DETAIL_ENGINE_PULSECOUNTENGINE_H_INCLUDED + +#endif \ No newline at end of file diff --git a/include/react/engine/SubtreeEngine.h b/include/react/engine/SubtreeEngine.h index cfda49d1..447c1184 100644 --- a/include/react/engine/SubtreeEngine.h +++ b/include/react/engine/SubtreeEngine.h @@ -4,6 +4,8 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) +#if 0 + #ifndef REACT_DETAIL_ENGINE_SUBTREEENGINE_H_INCLUDED #define REACT_DETAIL_ENGINE_SUBTREEENGINE_H_INCLUDED @@ -191,4 +193,6 @@ struct NodeUpdateTimerEnabled> : std::true_t /****************************************/ REACT_IMPL_END /***************************************/ -#endif // REACT_DETAIL_ENGINE_SUBTREEENGINE_H_INCLUDED \ No newline at end of file +#endif // REACT_DETAIL_ENGINE_SUBTREEENGINE_H_INCLUDED + +#endif \ No newline at end of file diff --git a/include/react/engine/ToposortEngine.h b/include/react/engine/ToposortEngine.h index 331ecd11..2575bbd9 100644 --- a/include/react/engine/ToposortEngine.h +++ b/include/react/engine/ToposortEngine.h @@ -4,6 +4,8 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) +#if 0 + #ifndef REACT_DETAIL_ENGINE_TOPOSORTENGINE_H_INCLUDED #define REACT_DETAIL_ENGINE_TOPOSORTENGINE_H_INCLUDED @@ -207,4 +209,6 @@ struct NodeUpdateTimerEnabled> : std::true_ /****************************************/ REACT_IMPL_END /***************************************/ -#endif // REACT_DETAIL_ENGINE_TOPOSORTENGINE_H_INCLUDED \ No newline at end of file +#endif // REACT_DETAIL_ENGINE_TOPOSORTENGINE_H_INCLUDED + +#endif \ No newline at end of file diff --git a/project/msvc/CppReact.vcxproj b/project/msvc/CppReact.vcxproj index f2e9c00c..0d380c1c 100644 --- a/project/msvc/CppReact.vcxproj +++ b/project/msvc/CppReact.vcxproj @@ -154,11 +154,12 @@ + - - + + @@ -167,11 +168,8 @@ - - - - - + + @@ -181,21 +179,16 @@ - - - - + - - diff --git a/project/msvc/CppReact.vcxproj.filters b/project/msvc/CppReact.vcxproj.filters index 2b7a6008..1174c9b1 100644 --- a/project/msvc/CppReact.vcxproj.filters +++ b/project/msvc/CppReact.vcxproj.filters @@ -25,15 +25,9 @@ {11a75126-8bfd-4693-be4b-4e06ab73450c} - - {f58215db-3a12-432a-a4c1-e24a90df70a9} - {3f444875-ab1a-4bbd-99eb-7018c930098a} - - {22da08e3-fb85-4fed-9fbc-8944ef866ccc} - @@ -51,9 +45,6 @@ Header Files\common - - Header Files - Header Files\common @@ -66,30 +57,12 @@ Header Files\detail - - Header Files\detail - - - Header Files\detail - Header Files\detail\graph Header Files\detail\graph - - Header Files\logging - - - Header Files\logging - - - Header Files\logging - - - Header Files - Header Files\detail @@ -102,30 +75,12 @@ Header Files\detail\graph - - Header Files\detail - - - Header Files - - - Header Files\detail - - - Header Files - Header Files\detail\graph Header Files\engine - - Header Files - - - Header Files - Header Files\common @@ -135,20 +90,35 @@ Header Files\common - + Header Files\detail - - Header Files\detail + + Header Files\detail\graph + + + Header Files\detail\graph + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files - - Source Files\logging - - - Source Files\logging - Source Files\engine @@ -158,5 +128,8 @@ Source Files\engine + + Source Files + \ No newline at end of file diff --git a/src/engine/PulsecountEngine.cpp b/src/engine/PulsecountEngine.cpp index 5fa3a844..0be62ba6 100644 --- a/src/engine/PulsecountEngine.cpp +++ b/src/engine/PulsecountEngine.cpp @@ -4,6 +4,8 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) +#if 0 + #include "react/engine/PulsecountEngine.h" #include @@ -281,4 +283,6 @@ void EngineBase::OnDynamicNodeDetach(Node& node, Node& parent, Turn& turn) }// ~parent.ShiftMutex (write) } // ~namespace pulsecount -/****************************************/ REACT_IMPL_END /***************************************/ \ No newline at end of file +/****************************************/ REACT_IMPL_END /***************************************/ + +#endif \ No newline at end of file diff --git a/src/engine/SubtreeEngine.cpp b/src/engine/SubtreeEngine.cpp index c71d6e0f..8584fcc2 100644 --- a/src/engine/SubtreeEngine.cpp +++ b/src/engine/SubtreeEngine.cpp @@ -4,6 +4,8 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) +#if 0 + #include "react/engine/SubtreeEngine.h" #include @@ -341,4 +343,6 @@ void EngineBase::invalidateSuccessors(Node& node) } } // ~namespace subtree -/****************************************/ REACT_IMPL_END /***************************************/ \ No newline at end of file +/****************************************/ REACT_IMPL_END /***************************************/ + +#endif \ No newline at end of file diff --git a/src/engine/ToposortEngine.cpp b/src/engine/ToposortEngine.cpp index 54612191..b8db5f67 100644 --- a/src/engine/ToposortEngine.cpp +++ b/src/engine/ToposortEngine.cpp @@ -4,6 +4,8 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) +#if 0 + #include "react/engine/ToposortEngine.h" #include "tbb/parallel_for.h" @@ -216,4 +218,6 @@ void ParEngineBase::invalidateSuccessors(ParNode& node) } } // ~namespace toposort -/****************************************/ REACT_IMPL_END /***************************************/ \ No newline at end of file +/****************************************/ REACT_IMPL_END /***************************************/ + +#endif \ No newline at end of file From 54d1f02576b09229cf9f2cb7e66f912e197cdf27 Mon Sep 17 00:00:00 2001 From: schlangster Date: Fri, 5 Aug 2016 03:18:28 +0200 Subject: [PATCH 31/75] Redesign progress. --- include/react/Algorithm.h | 51 ++-- include/react/Event.h | 270 +++++++------------- include/react/Signal.h | 105 ++++---- include/react/detail/ObserverBase.h | 2 - include/react/detail/graph/AlgorithmNodes.h | 4 +- include/react/detail/graph/EventNodes.h | 26 +- 6 files changed, 189 insertions(+), 269 deletions(-) diff --git a/include/react/Algorithm.h b/include/react/Algorithm.h index e2a1f3a9..d41d0fef 100644 --- a/include/react/Algorithm.h +++ b/include/react/Algorithm.h @@ -23,41 +23,34 @@ /////////////////////////////////////////////////////////////////////////////////////////////////// /// Hold - Hold the most recent event in a signal /////////////////////////////////////////////////////////////////////////////////////////////////// -template -auto Hold(const Events& events, U&& init) -> Signal +template +auto Hold(T&& initialValue, const EventBase& events) -> Signal { using REACT_IMPL::HoldNode; + using REACT_IMPL::PrivateNodeInterface; - return Signal( - std::make_shared>( - std::forward(init), GetNodePtr(events))); + return Signal( std::make_shared>( + PrivateNodeInterface::GraphPtr(events), std::forward(initialValue), PrivateNodeInterface::NodePtr(events)) ); } /////////////////////////////////////////////////////////////////////////////////////////////////// /// Monitor - Emits value changes of target signal /////////////////////////////////////////////////////////////////////////////////////////////////// -template -auto Monitor(const Signal& target) -> Events +template +auto Monitor(const SignalBase& signal) -> Event { using REACT_IMPL::MonitorNode; + using REACT_IMPL::PrivateNodeInterface; - return Events( - std::make_shared>( - GetNodePtr(target))); + return Event( std::make_shared>( + PrivateNodeInterface::GraphPtr(signal), PrivateNodeInterface::NodePtr(signal)) ); } /////////////////////////////////////////////////////////////////////////////////////////////////// /// Iterate - Iteratively combines signal value with values from event stream (aka Fold) /////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename S, - typename E, - typename V, - typename F, - -> -auto Iterate(const Events& events, V&& init, F&& func) -> Signal +template +auto Iterate(T&& init, F&& func, const Events& events) -> Signal { using REACT_IMPL::IterateNode; using REACT_IMPL::IterateByRefNode; @@ -178,28 +171,28 @@ auto Iterate(const Events& events, V&& init, const SignalPack& /// Snapshot - Sets signal value to value of other signal when event is received /////////////////////////////////////////////////////////////////////////////////////////////////// template -auto Snapshot(const Events& trigger, const Signal& target) -> Signal +auto Snapshot(const Signal& signal, const Events& trigger) -> Signal { using REACT_IMPL::SnapshotNode; + using REACT_IMPL::GetCheckedGraphPtr; + using REACT_IMPL::PrivateNodeInterface; - return Signal( - std::make_shared>( - GetNodePtr(target), GetNodePtr(trigger))); + return Events( std::make_shared>( + GetCheckedGraphPtr(signal, trigger), PrivateNodeInterface::NodePtr(signal), PrivateNodeInterface::NodePtr(trigger)) ); } - - /////////////////////////////////////////////////////////////////////////////////////////////////// /// Pulse - Emits value of target signal when event is received /////////////////////////////////////////////////////////////////////////////////////////////////// template -auto Pulse(const Events& trigger, const Signal& target) -> Events +auto Pulse(const Signal& signal, const Events& trigger) -> Events { using REACT_IMPL::PulseNode; + using REACT_IMPL::GetCheckedGraphPtr; + using REACT_IMPL::PrivateNodeInterface; - return Events( - std::make_shared>( - GetNodePtr(target), GetNodePtr(trigger))); + return Events( std::make_shared>( + GetCheckedGraphPtr(signal, trigger), PrivateNodeInterface::NodePtr(signal), PrivateNodeInterface::NodePtr(trigger)) ); } /////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/include/react/Event.h b/include/react/Event.h index 5af37093..e244ec46 100644 --- a/include/react/Event.h +++ b/include/react/Event.h @@ -25,11 +25,11 @@ /// Events /////////////////////////////////////////////////////////////////////////////////////////////////// -template +template class EventBase { private: - using NodeType = REACT_IMPL::EventStreamNode; + using NodeType = REACT_IMPL::EventStreamNode; public: EventBase() = default; @@ -69,16 +69,26 @@ class EventBase auto NodePtr() const -> const std::shared_ptr& { return nodePtr_; } - template - auto CreateProcessingNode(FIn&& func, const EventBase& dep) -> decltype(auto) + template + auto CreateProcessingNode(F&& func, const EventBase& dep) -> decltype(auto) { - using F = typename std::decay::type; - using ProcessingNodeType = REACT_IMPL::EventProcessingNode; + using ProcessingNodeType = REACT_IMPL::EventProcessingNode::type>; return std::make_shared( REACT_IMPL::PrivateNodeInterface::GraphPtr(dep), - REACT_IMPL::PrivateNodeInterface::NodePtr(dep), - std::forward(func)); + std::forward(func), + REACT_IMPL::PrivateNodeInterface::NodePtr(dep)); + } + + template + auto CreateSyncedProcessingNode(F&& func, const EventBase& dep, const SignalBase ... syncs) -> decltype(auto) + { + using SyncedProcessingNodeType = REACT_IMPL::SyncedEventProcessingNode::type, Us ...>; + + return std::make_shared( + REACT_IMPL::GetCheckedGraphPtr(dep, syncs ...), + std::forward(func), + REACT_IMPL::PrivateNodeInterface::NodePtr(dep), REACT_IMPL::PrivateNodeInterface::NodePtr(syncs) ...); } private: @@ -90,11 +100,11 @@ class EventBase /////////////////////////////////////////////////////////////////////////////////////////////////// /// EventSource /////////////////////////////////////////////////////////////////////////////////////////////////// -template -class EventSourceBase : public EventBase +template +class EventSourceBase : public EventBase { private: - using NodeType = REACT_IMPL::EventSourceNode; + using NodeType = REACT_IMPL::EventSourceNode; public: using EventBase::EventBase; @@ -112,25 +122,25 @@ class EventSourceBase : public EventBase EventSourceBase::EventBase( std::make_shared(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group)) ) { } - void Emit(const T& value) + void Emit(const E& value) { EmitValue(value); } - void Emit(T&& value) + void Emit(E&& value) { EmitValue(std::move(value)); } - template ::value>::type> + template ::value>::type> void Emit() { EmitValue(Token::value); } - EventSourceBase& operator<<(const T& value) + EventSourceBase& operator<<(const E& value) { EmitValue(e); return *this; } - EventSourceBase& operator<<(T&& value) + EventSourceBase& operator<<(E&& value) { EmitValue(std::move(value)); return *this; } private: - template - void EmitValue(U&& value) + template + void EmitValue(T&& value) { using REACT_IMPL::NodeId; using REACT_IMPL::IReactiveGraph; @@ -139,20 +149,20 @@ class EventSourceBase : public EventBase NodeId nodeId = castedPtr->GetNodeId(); auto& graphPtr = NodePtr()->GraphPtr(); - graphPtr->AddInput(nodeId, [castedPtr, &value] { castedPtr->EmitValue(std::forward(value)); }); + graphPtr->AddInput(nodeId, [castedPtr, &value] { castedPtr->EmitValue(std::forward(value)); }); } }; /////////////////////////////////////////////////////////////////////////////////////////////////// /// Event /////////////////////////////////////////////////////////////////////////////////////////////////// -template -class Event : public EventBase +template +class Event : public EventBase { public: using EventBase::EventBase; - using ValueType = T; + using ValueType = E; Event() = delete; @@ -162,19 +172,24 @@ class Event : public EventBase Event(Event&&) = default; Event& operator=(Event&&) = default; - template - Event(F&& func, const EventBase& dep) : + template + Event(F&& func, const EventBase& dep) : Event::EventBase( CreateProcessingNode(std::forward(func), dep) ) { } + + template + Event(F&& func, const EventBase& dep, const SignalBase ... signals) : + Event::EventBase( CreateSyncedProcessingNode(std::forward(func), dep, signals ...) ) + { } }; -template -class Event : public EventBase +template +class Event : public EventBase { public: using EventBase::EventBase; - using ValueType = T; + using ValueType = E; Event() = delete; @@ -184,29 +199,34 @@ class Event : public EventBase Event(Event&&) = default; Event& operator=(Event&&) = default; - Event(Event&& other) : + Event(Event&& other) : Event::EventBase( std::move(other) ) { } - Event& operator=(Event&& other) + Event& operator=(Event&& other) { Event::EventBase::operator=(std::move(other)); return *this; } - template - Event(F&& func, const EventBase& dep) : + template + Event(F&& func, const EventBase& dep) : Event::EventBase( CreateProcessingNode(std::forward(func), dep) ) { } + + template + Event(F&& func, const EventBase& dep, const SignalBase ... signals) : + Event::EventBase( SyncedCreateProcessingNode(std::forward(func), dep, signals ...) ) + { } }; /////////////////////////////////////////////////////////////////////////////////////////////////// /// EventSource /////////////////////////////////////////////////////////////////////////////////////////////////// -template -class EventSource : public EventSourceBase +template +class EventSource : public EventSourceBase { public: using EventSourceBase::EventSourceBase; - using ValueType = T; + using ValueType = E; EventSource() = delete; @@ -217,13 +237,13 @@ class EventSource : public EventSourceBase EventSource& operator=(EventSource&&) = default; }; -template -class EventSource : public EventSourceBase +template +class EventSource : public EventSourceBase { public: using EventSourceBase::EventSourceBase; - using ValueType = T; + using ValueType = E; EventSource() = delete; @@ -233,11 +253,11 @@ class EventSource : public EventSourceBase EventSource(EventSource&&) = default; EventSource& operator=(EventSource&&) = default; - EventSource(EventSource&& other) : + EventSource(EventSource&& other) : EventSource::EventSourceBase( std::move(other) ) { } - EventSource& operator=(EventSource&& other) + EventSource& operator=(EventSource&& other) { EventSource::EventSourceBase::operator=(std::move(other)); return *this; } }; @@ -251,7 +271,7 @@ auto Merge(const EventBase& dep1, const EventBase& ... deps) -> decltype using REACT_IMPL::GetCheckedGraphPtr; using REACT_IMPL::PrivateNodeInterface; - static_assert(sizeof...(Us) > 0, "Merge: 2+ arguments are required."); + static_assert(sizeof...(Us) > 0, "Merge requires at least 2 inputs."); // If supplied, use merge type, otherwise default to common type. using E = typename std::conditional< @@ -268,174 +288,80 @@ auto Merge(const EventBase& dep1, const EventBase& ... deps) -> decltype /////////////////////////////////////////////////////////////////////////////////////////////////// /// Filter /////////////////////////////////////////////////////////////////////////////////////////////////// -template -auto Filter(F&& pred, const EventBase& dep) -> Event +template +auto Filter(F&& pred, const EventBase& dep) -> Event { - auto filterFunc = [capturedPred = std::forward(pred)] (EventRange inRange, EventSink out) + auto filterFunc = [capturedPred = std::forward(pred)] (EventRange inRange, EventSink out) { std::copy_if(inRange.begin(), inRange.end(), out, capturedPred); }; - return Event(std::move(filterFunc), dep); + return Event(std::move(filterFunc), dep); } -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Transform -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -auto Transform(F&& op, const EventBase& dep) -> Event +template +auto Filter(F&& pred, const EventBase& dep, const SignalBase& ... signals) -> Event { - auto transformFunc = [capturedPred = std::forward(op)] (EventRange inRange, EventSink out) - { std::transform(inRange.begin(), inRange.end(), out, pred); }; - - return Event(std::move(transformFunc), dep); -} - -#if 0 - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Filter - Synced -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename E, - typename FIn, - typename ... TDepValues -> -auto Filter(const Events& source, const SignalPack& depPack, FIn&& func) -> Events -{ - using REACT_IMPL::SyncedEventFilterNode; - - using F = typename std::decay::type; - - struct NodeBuilder_ + auto filterFunc = [capturedPred = std::forward(pred)] (EventRange inRange, EventSink out, const Us& ... values) { - NodeBuilder_(const Events& source, FIn&& func) : - MySource( source ), - MyFunc( std::forward(func) ) - {} - - auto operator()(const Signal& ... deps) - -> Events - { - return Events( - std::make_shared>( - GetNodePtr(MySource), std::forward(MyFunc), GetNodePtr(deps) ...)); - } - - const Events& MySource; - FIn MyFunc; + for (const auto& v : inRange) + if (capturedPred(v, values ...)) + *out++ = v; }; - return REACT_IMPL::apply( - NodeBuilder_( source, std::forward(func) ), - depPack.Data); + return Event(std::move(filterFunc), dep, signals ...); } - - /////////////////////////////////////////////////////////////////////////////////////////////////// -/// Transform - Synced +/// Transform /////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename TIn, - typename FIn, - typename ... TDepValues, - typename TOut = typename std::result_of::type -> -auto Transform(const Events& source, FIn&& func, const Signal& ... deps) -> Events +template +auto Transform(F&& op, const EventBase& dep) -> Event { - using REACT_IMPL::SyncedEventTransformNode; + auto transformFunc = [capturedOp = std::forward(op)] (EventRange inRange, EventSink out) + { std::transform(inRange.begin(), inRange.end(), out, capturedOp); }; - using F = typename std::decay::type; - - struct NodeBuilder_ - { - NodeBuilder_(const Events& source, FIn&& func) : - MySource( source ), - MyFunc( std::forward(func) ) - {} - - auto operator()(const Signal& ... deps) - -> Events - { - return Events( - std::make_shared>( - GetNodePtr(MySource), std::forward(MyFunc), GetNodePtr(deps) ...)); - } - - const Events& MySource; - FIn MyFunc; - }; - - return REACT_IMPL::apply( - NodeBuilder_( source, std::forward(func) ), - depPack.Data); + return Event(std::move(transformFunc), dep); } -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Process - Synced -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename TOut, - typename TIn, - typename FIn, - typename ... TDepValues -> -auto Process(const Events& source, const SignalPack& depPack, FIn&& func) -> Events +template +auto Transform(F&& op, const EventBase& dep, const SignalBase& ... signals) -> Event { - using REACT_IMPL::SyncedEventProcessingNode; - - using F = typename std::decay::type; - - struct NodeBuilder_ + auto transformFunc = [capturedOp = std::forward(pred)] (EventRange inRange, EventSink out, const Vs& ... values) { - NodeBuilder_(const Events& source, FIn&& func) : - MySource( source ), - MyFunc( std::forward(func) ) - {} - - auto operator()(const Signal& ... deps) - -> Events - { - return Events( - std::make_shared>( - GetNodePtr(MySource), std::forward(MyFunc), GetNodePtr(deps) ...)); - } - - const Events& MySource; - FIn MyFunc; + for (const auto& v : inRange) + *out++ = capturedPred(v, values ...); }; - return REACT_IMPL::apply( - NodeBuilder_( source, std::forward(func) ), - depPack.Data); + return Event(std::move(transformFunc), dep, signals ...); } /////////////////////////////////////////////////////////////////////////////////////////////////// /// Flatten /////////////////////////////////////////////////////////////////////////////////////////////////// -template +/*template auto Flatten(const Signal>& outer) -> Events { return Events( std::make_shared, TInnerValue>>( GetNodePtr(outer), GetNodePtr(outer.Value()))); -} +}*/ /////////////////////////////////////////////////////////////////////////////////////////////////// /// Join /////////////////////////////////////////////////////////////////////////////////////////////////// -template -auto Join(const Events& ... args) -> Events> +template +auto Join(const EventBase& ... deps) -> Event, unique> { using REACT_IMPL::EventJoinNode; + using REACT_IMPL::GetCheckedGraphPtr; + using REACT_IMPL::PrivateNodeInterface; + + static_assert(sizeof...(Ts) > 1, "Join requires at least 2 inputs."); - static_assert(sizeof...(TArgs) > 1, "Join: 2+ arguments are required."); + // If supplied, use merge type, otherwise default to common type. + const auto& graphPtr = GetCheckedGraphPtr(deps ...); - return Events< std::tuple>( - std::make_shared>( - GetNodePtr(args) ...)); + return Event, unique>( + std::make_shared>(graphPtr, PrivateNodeInterface::NodePtr(deps) ...)); } /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -443,7 +369,7 @@ auto Join(const Events& ... args) -> Events> /////////////////////////////////////////////////////////////////////////////////////////////////// enum class Token { value }; -struct Tokenizer +/*struct Tokenizer { template Token operator()(const T&) const { return Token::value; } @@ -453,9 +379,7 @@ template auto Tokenize(T&& source) -> decltype(auto) { return Transform(source, Tokenizer{ }); -} - -#endif +}*/ /******************************************/ REACT_END /******************************************/ diff --git a/include/react/Signal.h b/include/react/Signal.h index ea60ce3a..e8222bf3 100644 --- a/include/react/Signal.h +++ b/include/react/Signal.h @@ -29,11 +29,11 @@ /////////////////////////////////////////////////////////////////////////////////////////////////// /// SignalBase /////////////////////////////////////////////////////////////////////////////////////////////////// -template +template class SignalBase { private: - using NodeType = REACT_IMPL::SignalNode; + using NodeType = REACT_IMPL::SignalNode; public: SignalBase() = default; @@ -46,12 +46,12 @@ class SignalBase ~SignalBase() = default; - // Internal node ctor + // Private node ctor explicit SignalBase(std::shared_ptr&& nodePtr) : nodePtr_( std::move(nodePtr) ) { } - const T& Value() const + const S& Value() const { return nodePtr_->Value(); } protected: @@ -61,16 +61,18 @@ class SignalBase auto NodePtr() const -> const std::shared_ptr& { return nodePtr_; } - template - auto CreateFuncNode(FIn&& func, const SignalBase& dep1, const SignalBase& ... deps) -> decltype(auto) + template + auto CreateFuncNode(F&& func, const SignalBase& dep1, const SignalBase& ... deps) -> decltype(auto) { - using F = typename std::decay::type; - using FuncNodeType = REACT_IMPL::SignalFuncNode; + using REACT_IMPL::GetCheckedGraphPtr; + using REACT_IMPL::PrivateNodeInterface; + + using FuncNodeType = REACT_IMPL::SignalFuncNode::type, T1, Ts ...>; return std::make_shared( - REACT_IMPL::GetCheckedGraphPtr(dep1, deps ...), - std::forward(func), - REACT_IMPL::PrivateNodeInterface::NodePtr(dep1), REACT_IMPL::PrivateNodeInterface::NodePtr(deps) ...); + GetCheckedGraphPtr(dep1, deps ...), + std::forward(func), + PrivateNodeInterface::NodePtr(dep1), PrivateNodeInterface::NodePtr(deps) ...); } private: @@ -82,8 +84,8 @@ class SignalBase /////////////////////////////////////////////////////////////////////////////////////////////////// /// VarSignalBase /////////////////////////////////////////////////////////////////////////////////////////////////// -template -class VarSignalBase : public SignalBase +template +class VarSignalBase : public SignalBase { public: using SignalBase::SignalBase; @@ -96,16 +98,16 @@ class VarSignalBase : public SignalBase VarSignalBase(VarSignalBase&&) = default; VarSignalBase& operator=(VarSignalBase&&) = default; - void Set(const T& newValue) + void Set(const S& newValue) { SetValue(newValue); } - void Set(T&& newValue) + void Set(S&& newValue) { SetValue(std::move(newValue)); } - void operator<<=(const T& newValue) + void operator<<=(const S& newValue) { SetValue(newValue); } - void operator<<=(T&& newValue) + void operator<<=(S&& newValue) { SetValue(std::move(newValue)); } template @@ -113,26 +115,29 @@ class VarSignalBase : public SignalBase { ModifyValue(func); } protected: - template - auto CreateVarNode(U&& value, const TGroup& group) -> decltype(auto) + template + auto CreateVarNode(T&& value, const TGroup& group) -> decltype(auto) { - using VarNodeType = REACT_IMPL::VarSignalNode; - return std::make_shared(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), std::forward(value)); + using REACT_IMPL::PrivateReactiveGroupInterface; + + using VarNodeType = REACT_IMPL::VarSignalNode; + + return std::make_shared(PrivateReactiveGroupInterface::GraphPtr(group), std::forward(value)); } private: - template - void SetValue(U&& newValue) + template + void SetValue(T&& newValue) { using REACT_IMPL::NodeId; using REACT_IMPL::IReactiveGraph; - using VarNodeType = REACT_IMPL::VarSignalNode; + using VarNodeType = REACT_IMPL::VarSignalNode; VarNodeType* castedPtr = static_cast(this->NodePtr().get()); NodeId nodeId = castedPtr->GetNodeId(); auto& graphPtr = NodePtr()->GraphPtr(); - graphPtr->AddInput(nodeId, [castedPtr, &newValue] { castedPtr->SetValue(std::forward(newValue)); }); + graphPtr->AddInput(nodeId, [castedPtr, &newValue] { castedPtr->SetValue(std::forward(newValue)); }); } template @@ -140,7 +145,7 @@ class VarSignalBase : public SignalBase { using REACT_IMPL::NodeId; using REACT_IMPL::IReactiveGraph; - using VarNodeType = REACT_IMPL::VarSignalNode; + using VarNodeType = REACT_IMPL::VarSignalNode; VarNodeType* castedPtr = static_cast(this->NodePtr().get()); @@ -153,13 +158,13 @@ class VarSignalBase : public SignalBase /////////////////////////////////////////////////////////////////////////////////////////////////// /// Signal /////////////////////////////////////////////////////////////////////////////////////////////////// -template -class Signal : public SignalBase +template +class Signal : public SignalBase { public: using SignalBase::SignalBase; - using ValueType = T; + using ValueType = S; Signal() = delete; @@ -175,13 +180,13 @@ class Signal : public SignalBase { } }; -template -class Signal : public SignalBase +template +class Signal : public SignalBase { public: using SignalBase::SignalBase; - using ValueType = T; + using ValueType = S; Signal() = delete; @@ -191,15 +196,15 @@ class Signal : public SignalBase Signal(Signal&&) = default; Signal& operator=(Signal&&) = default; - Signal(Signal&& other) : + Signal(Signal&& other) : Signal::SignalBase( std::move(other) ) { } - Signal& operator=(Signal&& other) + Signal& operator=(Signal&& other) { Signal::SignalBase::operator=(std::move(other)); return *this; } - template - Signal(F&& func, const SignalBase& ... deps) : + template + Signal(F&& func, const SignalBase& ... deps) : Signal::SignalBase( CreateFuncNode(std::forward(func), deps ...) ) { } }; @@ -207,13 +212,13 @@ class Signal : public SignalBase /////////////////////////////////////////////////////////////////////////////////////////////////// /// Signal /////////////////////////////////////////////////////////////////////////////////////////////////// -template -class VarSignal : public VarSignalBase +template +class VarSignal : public VarSignalBase { public: using VarSignalBase::VarSignalBase; - using ValueType = T; + using ValueType = S; VarSignal() = delete; @@ -223,19 +228,19 @@ class VarSignal : public VarSignalBase VarSignal(VarSignal&&) = default; VarSignal& operator=(VarSignal&&) = default; - template - VarSignal(U&& value, const TGroup& group) : - VarSignal::VarSignalBase( CreateVarNode(std::forward(value), group) ) + template + VarSignal(T&& value, const TGroup& group) : + VarSignal::VarSignalBase( CreateVarNode(std::forward(value), group) ) { } }; -template -class VarSignal : public VarSignalBase +template +class VarSignal : public VarSignalBase { public: using VarSignalBase::VarSignalBase; - using ValueType = T; + using ValueType = S; VarSignal() = delete; @@ -245,16 +250,16 @@ class VarSignal : public VarSignalBase VarSignal(VarSignal&&) = default; VarSignal& operator=(VarSignal&&) = default; - VarSignal(VarSignal&& other) : + VarSignal(VarSignal&& other) : VarSignal::VarSignalBase( std::move(other) ) { } - VarSignal& operator=(VarSignal&& other) + VarSignal& operator=(VarSignal&& other) { VarSignal::SignalBase::operator=(std::move(other)); return *this; } - template - VarSignal(U&& value, const TGroup& group) : - VarSignal::VarSignalBase( CreateVarNode(std::forward(value), group) ) + template + VarSignal(T&& value, const TGroup& group) : + VarSignal::VarSignalBase( CreateVarNode(std::forward(value), group) ) { } }; diff --git a/include/react/detail/ObserverBase.h b/include/react/detail/ObserverBase.h index 73f637fd..6653ff04 100644 --- a/include/react/detail/ObserverBase.h +++ b/include/react/detail/ObserverBase.h @@ -15,8 +15,6 @@ #include #include -#include "IReactiveNode.h" - /***************************************/ REACT_IMPL_BEGIN /**************************************/ /////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/include/react/detail/graph/AlgorithmNodes.h b/include/react/detail/graph/AlgorithmNodes.h index 4c4fdc35..e3b8d584 100644 --- a/include/react/detail/graph/AlgorithmNodes.h +++ b/include/react/detail/graph/AlgorithmNodes.h @@ -86,10 +86,10 @@ class IterateNode : public SignalNode { public: template - IterateNode(const std::shared_ptr& graphPtr, U&& init, const std::shared_ptr>& events, V&& func) : + IterateNode(const std::shared_ptr& graphPtr, U&& init, const std::shared_ptr>& events, FIn&& func) : IterateNode::SignalNode( graphPtr, std::forward(init) ), events_( events ), - func_( std::forward(func) ) + func_( std::forward(func) ) { this->RegisterMe(); this->AttachToMe(events->GetNodeId()); diff --git a/include/react/detail/graph/EventNodes.h b/include/react/detail/graph/EventNodes.h index a68df789..124636fc 100644 --- a/include/react/detail/graph/EventNodes.h +++ b/include/react/detail/graph/EventNodes.h @@ -293,11 +293,11 @@ template class EventProcessingNode : public EventStreamNode { public: - template - EventProcessingNode(const std::shared_ptr& graphPtr, const std::shared_ptr>& dep, U&& func) : + template + EventProcessingNode(const std::shared_ptr& graphPtr, FIn&& func, const std::shared_ptr>& dep) : EventProcessingNode::EventStreamNode( graphPtr ), - dep_( dep ), - func_( std::forward(func) ) + func_( std::forward(func) ), + dep_( dep ) { this->RegisterMe(); this->AttachToMe(dep->GetNodeId()); @@ -328,9 +328,9 @@ class EventProcessingNode : public EventStreamNode { return 1; } private: - std::shared_ptr> dep_; - F func_; + + std::shared_ptr> dep_; }; /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -340,11 +340,11 @@ template class SyncedEventProcessingNode : public EventStreamNode { public: - template - SyncedEventProcessingNode(const std::shared_ptr& graphPtr, const std::shared_ptr>& dep, U&& func, const std::shared_ptr>& ... syncs) : + template + SyncedEventProcessingNode(const std::shared_ptr& graphPtr, FIn&& func, const std::shared_ptr>& dep, const std::shared_ptr>& ... syncs) : SyncedEventProcessingNode::EventStreamNode( graphPtr ), + func_( std::forward(func) ), dep_( dep ), - func_( std::forward(func) ), syncHolder_( syncs ... ) { this->RegisterMe(); @@ -364,7 +364,7 @@ class SyncedEventProcessingNode : public EventStreamNode this->SetCurrentTurn(turnId, true); // Update of this node could be triggered from deps, // so make sure source doesnt contain events from last turn - source_->SetCurrentTurn(turnId); + dep_->SetCurrentTurn(turnId); apply( [this] (const auto& ... syncs) @@ -386,10 +386,10 @@ class SyncedEventProcessingNode : public EventStreamNode { return 1 + sizeof...(TSyncs); } private: - std::shared_ptr> dep_; - F func_; + std::shared_ptr> dep_; + std::tuple>...> syncHolder_; }; @@ -473,7 +473,7 @@ class EventJoinNode : public EventStreamNode> template static void FetchBuffer(TurnId turnId, Slot& slot) { - slot.Source->SetCurrentTurn(turnId); + slot.source->SetCurrentTurn(turnId); slot.buffer.insert(slot.buffer.end(), slot.source->Events().begin(), slot.source->Events().end()); } From bd4c67ad0f6e5c511b7910b043c72458c6897e71 Mon Sep 17 00:00:00 2001 From: schlangster Date: Sat, 6 Aug 2016 17:45:04 +0200 Subject: [PATCH 32/75] Redesign progress. --- examples/src/BasicSignals.cpp | 337 ++++------------- include/react/API.h | 7 + include/react/Algorithm.h | 30 +- include/react/Event.h | 88 +++-- include/react/Group.h | 28 +- include/react/Observer.h | 403 +++++++-------------- include/react/Reactor.h | 76 ---- include/react/Signal.h | 81 +++-- include/react/detail/EngineBase.h | 49 --- include/react/detail/ObserverBase.h | 77 ---- include/react/detail/graph/EventNodes.h | 6 +- include/react/detail/graph/GraphBase.h | 4 +- include/react/detail/graph/ObserverNodes.h | 95 +++-- include/react/detail/graph/SignalNodes.h | 84 +++-- project/msvc/CppReact.vcxproj | 2 - project/msvc/CppReact.vcxproj.filters | 6 - 16 files changed, 415 insertions(+), 958 deletions(-) delete mode 100644 include/react/Reactor.h delete mode 100644 include/react/detail/EngineBase.h delete mode 100644 include/react/detail/ObserverBase.h diff --git a/examples/src/BasicSignals.cpp b/examples/src/BasicSignals.cpp index 7f6943f2..bebdf7bf 100644 --- a/examples/src/BasicSignals.cpp +++ b/examples/src/BasicSignals.cpp @@ -12,7 +12,8 @@ #include #include "react/Signal.h" -/* +#include "react/Observer.h" + /////////////////////////////////////////////////////////////////////////////////////////////////// /// Example 1 - Hello world /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -21,74 +22,37 @@ namespace example1 using namespace std; using namespace react; - // Defines a domain. + // The concat function + string ConcatFunc(string first, string second) + { return first + string(" ") + second; } + + // Defines a group. // Each domain represents a separate dependency graph, managed by a dedicated propagation engine. // Reactives of different domains can not be combined. - ReactiveGroup - - // 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; - } + ReactiveGroup<> group; + + // The two words + VarSignal firstWord( string("Change"), group ); + VarSignal secondWord( string("me!"), group ); // A signal that concatenates both words - namespace v1 - { - // The two words - VarSignalT firstWord( string("Change") ); - VarSignalT secondWord( 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; - } - } + Signal bothWords(ConcatFunc, firstWord, secondWord); - // Using overloaded operator + instead of explicit MakeSignal - namespace v2 + void Run() { - // The two words - VarSignalT firstWord = MakeVar(string("Change")); - VarSignalT secondWord = MakeVar(string("me!")); - - SignalT bothWords = firstWord + string(" ") + secondWord; + cout << "Example 1 - Hello world" << endl; - void Run() - { - cout << "Example 1 - Hello world (operators)" << endl; + cout << bothWords.Value() << endl; - cout << bothWords.Value() << endl; + firstWord <<= string("Hello"); - firstWord <<= string("Hello"); + cout << bothWords.Value() << endl; - cout << bothWords.Value() << endl; + secondWord <<= string("World"); - secondWord <<= string("World"); + cout << bothWords.Value() << endl; - cout << bothWords.Value() << endl; - - cout << endl; - } + cout << endl; } } @@ -100,19 +64,19 @@ namespace example2 using namespace std; using namespace react; - REACTIVE_DOMAIN(D, sequential) - USING_REACTIVE_DOMAIN(D) + ReactiveGroup<> group; - VarSignalT x = MakeVar(1); - SignalT xAbs = MakeSignal(x, [] (int x) { return abs(x); }); + VarSignal x( 1, group ); + + Signal xAbs( [] (int v) { return abs(v); }, x); void Run() { cout << "Example 2 - Reacting to value changes" << endl; - Observe(xAbs, [] (int newValue) { - cout << "xAbs changed to " << newValue << endl; - }); + Observer<> obs( + [] (int newValue) { cout << "xAbs changed to " << newValue << endl; }, + xAbs ); // initially x is 1 x <<= 2; // output: xAbs changed to 2 @@ -131,28 +95,31 @@ namespace example3 using namespace std; using namespace react; - REACTIVE_DOMAIN(D, sequential) - USING_REACTIVE_DOMAIN(D) + int sumFunc(int a, int b) + { return a + b; } + + ReactiveGroup<> group; - VarSignalT a = MakeVar(1); - VarSignalT b = MakeVar(1); + VarSignal a( 1, group ); + VarSignal b( 1, group ); - SignalT x = a + b; - SignalT y = a + b; - SignalT z = x + y; + Signal x( sumFunc, a, b ); + Signal y( sumFunc, a, b ); + Signal z( sumFunc, x, y ); void Run() { cout << "Example 3 - Changing multiple inputs" << endl; - Observe(z, [] (int newValue) { - std::cout << "z changed to " << newValue << std::endl; - }); + Observer<> obs( + [] (int newValue) { cout << "z changed to " << newValue << endl; }, + z ); a <<= 2; // output: z changed to 6 b <<= 2; // output: z changed to 8 - DoTransaction([] { + group.DoTransaction([&] + { a <<= 4; b <<= 4; }); // output: z changed to 16 @@ -169,27 +136,24 @@ namespace example4 using namespace std; using namespace react; - REACTIVE_DOMAIN(D, sequential) - USING_REACTIVE_DOMAIN(D) + ReactiveGroup<> group; - VarSignalT> data = MakeVar(vector{ }); + VarSignal> data( group ); 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("Hello"); }); - data.Modify([] (vector& data) { - data.push_back("World"); - }); + data.Modify([] (vector& data) + { data.push_back("World"); }); for (const auto& s : data.Value()) cout << s << " "; cout << endl; - // output: Hell World + // output: Hello World cout << endl; } @@ -203,168 +167,49 @@ namespace example5 using namespace std; using namespace react; - REACTIVE_DOMAIN(D, sequential) - USING_REACTIVE_DOMAIN(D) + ReactiveGroup<> group; // Helpers - using ExprPairT = pair; - using ExprVectT = vector; + using ExprPairType = pair; + using ExprVectType = vector; - string makeExprStr(int a, int b, const char* op) + 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) + void PrintExpressions(const ExprVectType& 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; - } - } + // Input operands + VarSignal a( 1, group ); + VarSignal b( 2, group ); - // 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() + // The expression vector + Signal expressions( + [] (int a, int b) { - 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)); - + ExprVectType 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; - }); + }, a, b ); - void Run() - { - cout << "Example 5 - Complex signals (v3)" << endl; + void Run() + { + cout << "Example 5 - Complex signals (v3)" << endl; - Observe(expressions, printExpressions); + Observer<> obs(PrintExpressions, expressions); - a <<= 50; - b <<= 60; + a <<= 50; + b <<= 60; - cout << endl; - } + cout << endl; } } @@ -373,45 +218,11 @@ namespace example5 /////////////////////////////////////////////////////////////////////////////////////////////////// int main() { - example1::v1::Run(); - example1::v2::Run(); - + example1::Run(); example2::Run(); - example3::Run(); - example4::Run(); - - example5::v1::Run(); - example5::v2::Run(); - example5::v3::Run(); - - return 0; -} - -*/ - -using namespace react; - -int main() -{ - auto group = ReactiveGroup( ); - - auto sig1 = VarSignal( 1, group ); - auto sig2 = VarSignal( 2, group ); - - sig1.Set(1); - sig1 <<= 1; - - sig2.Modify([] (int& value) { value = 3; }); - - group.DoTransaction( - [&] - { - sig1 <<= 2; - }); - - auto sig3 = Signal( [] (auto a, auto b) { return a + b; }, sig1, sig2 ); + example5::Run(); return 0; } \ No newline at end of file diff --git a/include/react/API.h b/include/react/API.h index b445b74c..68b6f531 100644 --- a/include/react/API.h +++ b/include/react/API.h @@ -23,6 +23,12 @@ enum OwnershipPolicy shared }; +enum ReferencePolicy +{ + strong, + weak +}; + enum ThreadingPolicy { sequential, @@ -81,6 +87,7 @@ class EventSource; enum class Token; // Observers +template class Observer; /////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/include/react/Algorithm.h b/include/react/Algorithm.h index d41d0fef..e6624d74 100644 --- a/include/react/Algorithm.h +++ b/include/react/Algorithm.h @@ -171,7 +171,7 @@ auto Iterate(const Events& events, V&& init, const SignalPack& /// Snapshot - Sets signal value to value of other signal when event is received /////////////////////////////////////////////////////////////////////////////////////////////////// template -auto Snapshot(const Signal& signal, const Events& trigger) -> Signal +auto Snapshot(const SignalBase& signal, const EventBase& trigger) -> Signal { using REACT_IMPL::SnapshotNode; using REACT_IMPL::GetCheckedGraphPtr; @@ -185,40 +185,16 @@ auto Snapshot(const Signal& signal, const Events& trigger) -> Signal /// Pulse - Emits value of target signal when event is received /////////////////////////////////////////////////////////////////////////////////////////////////// template -auto Pulse(const Signal& signal, const Events& trigger) -> Events +auto Pulse(const SignalBase& signal, const EventBase& trigger) -> Event { using REACT_IMPL::PulseNode; using REACT_IMPL::GetCheckedGraphPtr; using REACT_IMPL::PrivateNodeInterface; - return Events( std::make_shared>( + return Event( std::make_shared>( GetCheckedGraphPtr(signal, trigger), PrivateNodeInterface::NodePtr(signal), PrivateNodeInterface::NodePtr(trigger)) ); } -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Changed - Emits token when target signal was changed -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -auto Changed(const Signal& target) -> Events -{ - return Monitor(target).Tokenize(); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// ChangedTo - Emits token when target signal was changed to value -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename T, - typename V, -> -auto ChangedTo(const Signal& target, V&& value) -> Events -{ - return Monitor(target) - .Filter([=] (const S& v) { return v == value; }) - .Tokenize(); -} - /******************************************/ REACT_END /******************************************/ #endif // REACT_ALGORITHM_H_INCLUDED \ No newline at end of file diff --git a/include/react/Event.h b/include/react/Event.h index e244ec46..637268ff 100644 --- a/include/react/Event.h +++ b/include/react/Event.h @@ -24,7 +24,6 @@ /////////////////////////////////////////////////////////////////////////////////////////////////// /// Events /////////////////////////////////////////////////////////////////////////////////////////////////// - template class EventBase { @@ -32,16 +31,6 @@ class EventBase using NodeType = REACT_IMPL::EventStreamNode; public: - EventBase() = default; - - EventBase(const EventBase&) = default; - EventBase& operator=(const EventBase&) = default; - - EventBase(EventBase&&) = default; - EventBase& operator=(EventBase&&) = default; - - ~EventBase() = default; - // Node ctor explicit EventBase(std::shared_ptr&& nodePtr) : nodePtr_( std::move(nodePtr) ) @@ -63,6 +52,14 @@ class EventBase { return REACT::Transform(*this, std::forward(f)); }*/ protected: + EventBase() = default; + + EventBase(const EventBase&) = default; + EventBase& operator=(const EventBase&) = default; + + EventBase(EventBase&&) = default; + EventBase& operator=(EventBase&&) = default; + auto NodePtr() -> std::shared_ptr& { return nodePtr_; } @@ -72,23 +69,23 @@ class EventBase template auto CreateProcessingNode(F&& func, const EventBase& dep) -> decltype(auto) { - using ProcessingNodeType = REACT_IMPL::EventProcessingNode::type>; + using REACT_IMPL::PrivateNodeInterface; + using EventNodeType = REACT_IMPL::EventProcessingNode::type>; - return std::make_shared( - REACT_IMPL::PrivateNodeInterface::GraphPtr(dep), - std::forward(func), - REACT_IMPL::PrivateNodeInterface::NodePtr(dep)); + return std::make_shared(PrivateNodeInterface::GraphPtr(dep), std::forward(func), PrivateNodeInterface::NodePtr(dep)); } template - auto CreateSyncedProcessingNode(F&& func, const EventBase& dep, const SignalBase ... syncs) -> decltype(auto) + auto CreateSyncedProcessingNode(F&& func, const EventBase& dep, const SignalBase& ... syncs) -> decltype(auto) { - using SyncedProcessingNodeType = REACT_IMPL::SyncedEventProcessingNode::type, Us ...>; + using REACT_IMPL::GetCheckedGraphPtr; + using REACT_IMPL::PrivateNodeInterface; + using EventNodeType = REACT_IMPL::SyncedEventProcessingNode::type, Us ...>; - return std::make_shared( - REACT_IMPL::GetCheckedGraphPtr(dep, syncs ...), + return std::make_shared( + GetCheckedGraphPtr(dep, syncs ...), std::forward(func), - REACT_IMPL::PrivateNodeInterface::NodePtr(dep), REACT_IMPL::PrivateNodeInterface::NodePtr(syncs) ...); + PrivateNodeInterface::NodePtr(dep), PrivateNodeInterface::NodePtr(syncs) ...); } private: @@ -108,19 +105,6 @@ class EventSourceBase : public EventBase public: using EventBase::EventBase; - - EventSourceBase() = default; - - EventSourceBase(const EventSourceBase&) = default; - EventSourceBase& operator=(const EventSourceBase&) = default; - - EventSourceBase(EventSourceBase&& other) = default; - EventSourceBase& operator=(EventSourceBase&& other) = default; - - template - explicit EventSourceBase(const TGroup& group) : - EventSourceBase::EventBase( std::make_shared(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group)) ) - { } void Emit(const E& value) { EmitValue(value); } @@ -138,6 +122,24 @@ class EventSourceBase : public EventBase EventSourceBase& operator<<(E&& value) { EmitValue(std::move(value)); return *this; } +protected: + EventSourceBase() = default; + + EventSourceBase(const EventSourceBase&) = default; + EventSourceBase& operator=(const EventSourceBase&) = default; + + EventSourceBase(EventSourceBase&& other) = default; + EventSourceBase& operator=(EventSourceBase&& other) = default; + + template + auto CreateSourceNode(const TGroup& group) -> decltype(auto) + { + using REACT_IMPL::PrivateReactiveGroupInterface; + using SrcNodeType = REACT_IMPL::EventSourceNode; + + return std::make_shared(PrivateReactiveGroupInterface::GraphPtr(group)); + } + private: template void EmitValue(T&& value) @@ -178,7 +180,7 @@ class Event : public EventBase { } template - Event(F&& func, const EventBase& dep, const SignalBase ... signals) : + Event(F&& func, const EventBase& dep, const SignalBase& ... signals) : Event::EventBase( CreateSyncedProcessingNode(std::forward(func), dep, signals ...) ) { } }; @@ -212,7 +214,7 @@ class Event : public EventBase { } template - Event(F&& func, const EventBase& dep, const SignalBase ... signals) : + Event(F&& func, const EventBase& dep, const SignalBase& ... signals) : Event::EventBase( SyncedCreateProcessingNode(std::forward(func), dep, signals ...) ) { } }; @@ -235,6 +237,12 @@ class EventSource : public EventSourceBase EventSource(EventSource&&) = default; EventSource& operator=(EventSource&&) = default; + + // Construct event source + template + explicit EventSource(const TGroup& group) : + EventSource::EventSourceBase( CreateSourceNode(group) ) + { } }; template @@ -253,10 +261,18 @@ class EventSource : public EventSourceBase EventSource(EventSource&&) = default; EventSource& operator=(EventSource&&) = default; + // Construct event source + template + explicit EventSource(const TGroup& group) : + EventSource::EventSourceBase( CreateSourceNode(group) ) + { } + + // Construct from unique EventSource(EventSource&& other) : EventSource::EventSourceBase( std::move(other) ) { } + // Assign from unique EventSource& operator=(EventSource&& other) { EventSource::EventSourceBase::operator=(std::move(other)); return *this; } }; diff --git a/include/react/Group.h b/include/react/Group.h index cf58e72a..71434d1e 100644 --- a/include/react/Group.h +++ b/include/react/Group.h @@ -86,23 +86,6 @@ class TransactionStatus friend void AsyncTransaction(TransactionFlagsT flags, TransactionStatus& status, F&& func); }; -/////////////////////////////////////////////////////////////////////////////////////////////// -/// DoTransaction -/////////////////////////////////////////////////////////////////////////////////////////////// -template -void DoTransaction(F&& func) -{ - using REACT_IMPL::DomainSpecificInputManager; - DomainSpecificInputManager::Instance().DoTransaction(0, std::forward(func)); -} - -template -void DoTransaction(TransactionFlags flags, F&& func) -{ - using REACT_IMPL::DomainSpecificInputManager; - DomainSpecificInputManager::Instance().DoTransaction(flags, std::forward(func)); -} - /////////////////////////////////////////////////////////////////////////////////////////////// /// AsyncTransaction /////////////////////////////////////////////////////////////////////////////////////////////// @@ -221,6 +204,15 @@ class ReactiveGroup : public ReactiveGroupBase ReactiveGroup(ReactiveGroup&& other) = default; ReactiveGroup& operator=(ReactiveGroup&& other) = default; + + // Construct from unique + ReactiveGroup(ReactiveGroup&& other) : + ReactiveGroup::ReactiveGroupBase( std::move(other) ) + { } + + // Assign from unique + ReactiveGroup& operator=(ReactiveGroup&& other) + { ReactiveGroup::ReactiveGroupBase::operator=(std::move(other)); return *this; } }; /******************************************/ REACT_END /******************************************/ @@ -260,7 +252,7 @@ static auto GetCheckedGraphPtr(const TBase1& dep1, const TBases& ... deps) -> co { const std::shared_ptr& graphPtr1 = PrivateNodeInterface::GraphPtr(dep1); - auto rawGraphPtrs = { PrivateNodeInterface::GraphPtr(deps).get() ... }; + std::initializer_list rawGraphPtrs = { PrivateNodeInterface::GraphPtr(deps).get() ... }; bool isSameGraphForAllDeps = std::all_of(rawGraphPtrs.begin(), rawGraphPtrs.end(), [&] (IReactiveGraph* p) { return p == graphPtr1.get(); }); diff --git a/include/react/Observer.h b/include/react/Observer.h index 705d4ee9..9d5c6409 100644 --- a/include/react/Observer.h +++ b/include/react/Observer.h @@ -4,337 +4,176 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -#if 0 - #ifndef REACT_OBSERVER_H_INCLUDED #define REACT_OBSERVER_H_INCLUDED #pragma once #include "react/detail/Defs.h" +#include "react/API.h" +#include "react/Group.h" #include #include -#include "react/common/Util.h" -#include "react/detail/IReactiveNode.h" -#include "react/detail/ObserverBase.h" #include "react/detail/graph/ObserverNodes.h" /*****************************************/ REACT_BEGIN /*****************************************/ /////////////////////////////////////////////////////////////////////////////////////////////////// -/// Forward declarations -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -class Signal; - -template -class Events; - -using REACT_IMPL::ObserverAction; -using REACT_IMPL::WeightHint; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Observer +/// ObserverBase /////////////////////////////////////////////////////////////////////////////////////////////////// -class Observer +class ObserverBase { private: - using SubjectPtrT = std::shared_ptr>; - using NodeT = REACT_IMPL::ObserverNode; + using NodeType = REACT_IMPL::ObserverNode; public: - // Default ctor - Observer() : - nodePtr_( nullptr ), - subjectPtr_( nullptr ) - {} - - // Move ctor - Observer(Observer&& other) : - nodePtr_( other.nodePtr_ ), - subjectPtr_( std::move(other.subjectPtr_) ) - { - other.nodePtr_ = nullptr; - other.subjectPtr_.reset(); - } + // Private node ctor + explicit ObserverBase(std::shared_ptr&& nodePtr) : + nodePtr_( std::move(nodePtr) ) + { } - // Node ctor - Observer(NodeT* nodePtr, const SubjectPtrT& subjectPtr) : - nodePtr_( nodePtr ), - subjectPtr_( subjectPtr ) - {} + void Cancel() + { nodePtr_.reset(); } - // Move assignment - Observer& operator=(Observer&& other) - { - nodePtr_ = other.nodePtr_; - subjectPtr_ = std::move(other.subjectPtr_); + bool IsCancelled() const + { return nodePtr_ != nullptr; } - other.nodePtr_ = nullptr; - other.subjectPtr_.reset(); +protected: + ObserverBase() = default; - return *this; - } + ObserverBase(const ObserverBase&) = default; + ObserverBase& operator=(const ObserverBase&) = default; - // Deleted copy ctor and assignment - Observer(const Observer&) = delete; - Observer& operator=(const Observer&) = delete; + ObserverBase(ObserverBase&&) = default; + ObserverBase& operator=(ObserverBase&&) = default; - void Detach() - { - assert(IsValid()); - subjectPtr_->UnregisterObserver(nodePtr_); - } + auto NodePtr() -> std::shared_ptr& + { return nodePtr_; } - bool IsValid() const - { - return nodePtr_ != nullptr; - } + auto NodePtr() const -> const std::shared_ptr& + { return nodePtr_; } - void SetWeightHint(WeightHint weight) + template + auto CreateSignalObserverNode(F&& func, const SignalBase& dep1, const SignalBase& ... deps) -> decltype(auto) { - assert(IsValid()); - nodePtr_->SetWeightHint(weight); + using REACT_IMPL::GetCheckedGraphPtr; + using REACT_IMPL::PrivateNodeInterface; + using ObsNodeType = REACT_IMPL::SignalObserverNode::type, T1, Ts ...>; + + return std::make_shared( + GetCheckedGraphPtr(dep1, deps ...), + std::forward(func), + PrivateNodeInterface::NodePtr(dep1), PrivateNodeInterface::NodePtr(deps) ...); } -private: - // Owned by subject - NodeT* nodePtr_; - - // While the observer handle exists, the subject is not destroyed - SubjectPtrT subjectPtr_; -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// ScopedObserver -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -class ScopedObserver -{ -public: - // Move ctor - ScopedObserver(ScopedObserver&& other) : - obs_( std::move(other.obs_) ) - {} - - // Construct from observer - ScopedObserver(Observer&& obs) : - obs_( std::move(obs) ) - {} - - // Move assignment - ScopedObserver& operator=(ScopedObserver&& other) + template + auto CreateEventObserverNode(F&& func, const EventBase& dep) -> decltype(auto) { - obs_ = std::move(other.obs_); - } + using REACT_IMPL::PrivateNodeInterface; + using ObsNodeType = REACT_IMPL::EventObserverNode::type, T>; - // Deleted default ctor, copy ctor and assignment - ScopedObserver() = delete; - ScopedObserver(const ScopedObserver&) = delete; - ScopedObserver& operator=(const ScopedObserver&) = delete; - - ~ScopedObserver() - { - obs_.Detach(); + return std::make_shared(PrivateNodeInterface::GraphPtr(dep), std::forward(func), PrivateNodeInterface::NodePtr(dep)); } - bool IsValid() const + template + auto CreateSyncedEventObserverNode(F&& func, const EventBase& dep, const SignalBase& ... syncs) -> decltype(auto) { - return obs_.IsValid(); - } - - void SetWeightHint(WeightHint weight) - { - obs_.SetWeightHint(weight); + using REACT_IMPL::GetCheckedGraphPtr; + using REACT_IMPL::PrivateNodeInterface; + using ObsNodeType = REACT_IMPL::SyncedEventObserverNode::type, T, Us ...>; + + return std::make_shared( + GetCheckedGraphPtr(dep, syncs ...), + std::forward(func), + PrivateNodeInterface::NodePtr(dep), PrivateNodeInterface::NodePtr(syncs) ...); } private: - Observer obs_; + std::shared_ptr nodePtr_; + + friend struct REACT_IMPL::PrivateNodeInterface; }; /////////////////////////////////////////////////////////////////////////////////////////////////// -/// Observe - Signals +/// Observer /////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename D, - typename FIn, - typename S -> -auto Observe(const Signal& subject, FIn&& func) - -> Observer +template <> +class Observer : public ObserverBase { - using REACT_IMPL::IObserver; - using REACT_IMPL::ObserverNode; - using REACT_IMPL::SignalObserverNode; - using REACT_IMPL::AddDefaultReturnValueWrapper; - - using F = typename std::decay::type; - using R = typename std::result_of::type; - using WrapperT = AddDefaultReturnValueWrapper; - - // If return value of passed function is void, add ObserverAction::next as - // default return value. - using NodeT = typename std::conditional< - std::is_same::value, - SignalObserverNode, - SignalObserverNode - >::type; - - const auto& subjectPtr = GetNodePtr(subject); - - std::unique_ptr> nodePtr( new NodeT(subjectPtr, std::forward(func)) ); - ObserverNode* rawNodePtr = nodePtr.get(); +public: + using ObserverBase::ObserverBase; - subjectPtr->RegisterObserver(std::move(nodePtr)); + Observer() = delete; - return Observer( rawNodePtr, subjectPtr ); -} + Observer(const Observer&) = delete; + Observer& operator=(const Observer&) = delete; -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Observe - Events -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename D, - typename FIn, - typename E -> -auto Observe(const Events& subject, FIn&& func) - -> Observer -{ - using REACT_IMPL::IObserver; - using REACT_IMPL::ObserverNode; - using REACT_IMPL::EventObserverNode; - using REACT_IMPL::AddDefaultReturnValueWrapper; - using REACT_IMPL::AddObserverRangeWrapper; - using REACT_IMPL::IsCallableWith; - using REACT_IMPL::EventRange; - - using F = typename std::decay::type; - - using WrapperT = - typename std::conditional< - IsCallableWith>::value, - F, - typename std::conditional< - IsCallableWith::value, - AddObserverRangeWrapper, - typename std::conditional< - IsCallableWith>::value, - AddDefaultReturnValueWrapper, - typename std::conditional< - IsCallableWith::value, - AddObserverRangeWrapper>, - void - >::type - >::type - >::type - >::type; - - static_assert( - ! std::is_same::value, - "Observe: Passed function does not match any of the supported signatures."); - - using NodeT = EventObserverNode; - - const auto& subjectPtr = GetNodePtr(subject); - - std::unique_ptr> nodePtr( new NodeT(subjectPtr, std::forward(func)) ); - ObserverNode* rawNodePtr = nodePtr.get(); - - subjectPtr->RegisterObserver(std::move(nodePtr)); - - return Observer( rawNodePtr, subjectPtr ); -} + Observer(Observer&&) = default; + Observer& operator=(Observer&&) = default; + + // Construct signal observer + template + Observer(F&& func, const SignalBase& ... subjects) : + Observer::ObserverBase( CreateSignalObserverNode(std::forward(func), subjects ...) ) + { } + + // Construct event observer + template + Observer(F&& func, const EventBase& subject) : + Observer::ObserverBase( CreateEventObserverNode(std::forward(func), subject ) ) + { } + + // Constructed synced event observer + template + Observer(F&& func, const EventBase& subject, const SignalBase& ... signals) : + Observer::ObserverBase( CreateSyncedEventObserverNode(std::forward(func), subject, signals ...) ) + { } +}; -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Observe - Synced -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename D, - typename FIn, - typename E, - typename ... TDepValues -> -auto Observe(const Events& subject, - const SignalPack& depPack, FIn&& func) - -> Observer +template <> +class Observer : public ObserverBase { - using REACT_IMPL::IObserver; - using REACT_IMPL::ObserverNode; - using REACT_IMPL::SyncedObserverNode; - using REACT_IMPL::AddDefaultReturnValueWrapper; - using REACT_IMPL::AddObserverRangeWrapper; - using REACT_IMPL::IsCallableWith; - using REACT_IMPL::EventRange; - - using F = typename std::decay::type; - - using WrapperT = - typename std::conditional< - IsCallableWith, TDepValues ...>::value, - F, - typename std::conditional< - IsCallableWith::value, - AddObserverRangeWrapper, - typename std::conditional< - IsCallableWith, TDepValues ...>::value, - AddDefaultReturnValueWrapper, - typename std::conditional< - IsCallableWith::value, - AddObserverRangeWrapper, - TDepValues...>, - void - >::type - >::type - >::type - >::type; - - static_assert( - ! std::is_same::value, - "Observe: Passed function does not match any of the supported signatures."); - - using NodeT = SyncedObserverNode; - - struct NodeBuilder_ - { - NodeBuilder_(const Events& subject, FIn&& func) : - MySubject( subject ), - MyFunc( std::forward(func) ) - {} - - auto operator()(const Signal& ... deps) - -> ObserverNode* - { - return new NodeT( - GetNodePtr(MySubject), std::forward(MyFunc), GetNodePtr(deps) ... ); - } - - const Events& MySubject; - FIn MyFunc; - }; - - const auto& subjectPtr = GetNodePtr(subject); - - std::unique_ptr> nodePtr( REACT_IMPL::apply( - NodeBuilder_( subject, std::forward(func) ), - depPack.Data) ); - - ObserverNode* rawNodePtr = nodePtr.get(); - - subjectPtr->RegisterObserver(std::move(nodePtr)); - - return Observer( rawNodePtr, subjectPtr ); -} +public: + using ObserverBase::ObserverBase; + + Observer() = delete; + + Observer(const Observer&) = default; + Observer& operator=(const Observer&) = default; + + Observer(Observer&&) = default; + Observer& operator=(Observer&&) = default; + + // Construct from unique + Observer(Observer&& other) : + Observer::ObserverBase( std::move(other) ) + { } + + // Assign from unique + Observer& operator=(Observer&& other) + { Observer::ObserverBase::operator=(std::move(other)); return *this; } + + // Construct signal observer + template + Observer(F&& func, const SignalBase& ... subjects) : + Observer::ObserverBase( CreateSignalObserverNode(std::forward(func), subjects ...) ) + { } + + // Construct event observer + template + Observer(F&& func, const EventBase& subject) : + Observer::ObserverBase( CreateEventObserverNode(std::forward(func), subject ) ) + { } + + // Constructed synced event observer + template + Observer(F&& func, const EventBase& subject, const SignalBase& ... signals) : + Observer::ObserverBase( CreateSyncedEventObserverNode(std::forward(func), subject, signals ...) ) + { } +}; /******************************************/ REACT_END /******************************************/ -#endif // REACT_OBSERVER_H_INCLUDED - -#endif \ No newline at end of file +#endif // REACT_OBSERVER_H_INCLUDED \ No newline at end of file diff --git a/include/react/Reactor.h b/include/react/Reactor.h deleted file mode 100644 index 92d3b006..00000000 --- a/include/react/Reactor.h +++ /dev/null @@ -1,76 +0,0 @@ - -// Copyright Sebastian Jeckel 2016. -// 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) - -#ifndef REACT_REACTOR_H_INCLUDED -#define REACT_REACTOR_H_INCLUDED - -#pragma once - -#include "react/detail/Defs.h" - -#include -#include -#include - -#include "react/common/Util.h" - -#include "react/Event.h" -#include "react/detail/ReactiveBase.h" -#include "react/detail/graph/ReactorNodes.h" - -/*****************************************/ REACT_BEGIN /*****************************************/ - -template -class Reactor -{ -public: - class Context; - - using NodeT = REACT_IMPL::ReactorNode; - - class Context - { - public: - Context(NodeT& node) : - node_( node ) - {} - - template - E& Await(const Events& evn) - { - return node_.Await(GetNodePtr(evn)); - } - - template - void RepeatUntil(const Events& evn, F&& func) - { - node_.RepeatUntil(GetNodePtr(evn), std::forward(func)); - } - - template - const S& Get(const Signal& sig) - { - return node_.Get(GetNodePtr(sig)); - } - - private: - NodeT& node_; - }; - - template - explicit Reactor(F&& func) : - nodePtr_( new REACT_IMPL::ReactorNode(std::forward(func)) ) - { - nodePtr_->StartLoop(); - } - -private: - std::unique_ptr nodePtr_; -}; - -/******************************************/ REACT_END /******************************************/ - -#endif // REACT_REACTOR_H_INCLUDED \ No newline at end of file diff --git a/include/react/Signal.h b/include/react/Signal.h index e8222bf3..c46a0b94 100644 --- a/include/react/Signal.h +++ b/include/react/Signal.h @@ -36,16 +36,6 @@ class SignalBase using NodeType = REACT_IMPL::SignalNode; public: - SignalBase() = default; - - SignalBase(const SignalBase&) = default; - SignalBase& operator=(const SignalBase&) = default; - - SignalBase(SignalBase&&) = default; - SignalBase& operator=(SignalBase&&) = default; - - ~SignalBase() = default; - // Private node ctor explicit SignalBase(std::shared_ptr&& nodePtr) : nodePtr_( std::move(nodePtr) ) @@ -55,6 +45,14 @@ class SignalBase { return nodePtr_->Value(); } protected: + SignalBase() = default; + + SignalBase(const SignalBase&) = default; + SignalBase& operator=(const SignalBase&) = default; + + SignalBase(SignalBase&&) = default; + SignalBase& operator=(SignalBase&&) = default; + auto NodePtr() -> std::shared_ptr& { return nodePtr_; } @@ -66,7 +64,6 @@ class SignalBase { using REACT_IMPL::GetCheckedGraphPtr; using REACT_IMPL::PrivateNodeInterface; - using FuncNodeType = REACT_IMPL::SignalFuncNode::type, T1, Ts ...>; return std::make_shared( @@ -90,14 +87,6 @@ class VarSignalBase : public SignalBase public: using SignalBase::SignalBase; - VarSignalBase() = default; - - VarSignalBase(const VarSignalBase&) = default; - VarSignalBase& operator=(const VarSignalBase&) = default; - - VarSignalBase(VarSignalBase&&) = default; - VarSignalBase& operator=(VarSignalBase&&) = default; - void Set(const S& newValue) { SetValue(newValue); } @@ -115,11 +104,27 @@ class VarSignalBase : public SignalBase { ModifyValue(func); } protected: + VarSignalBase() = default; + + VarSignalBase(const VarSignalBase&) = default; + VarSignalBase& operator=(const VarSignalBase&) = default; + + VarSignalBase(VarSignalBase&&) = default; + VarSignalBase& operator=(VarSignalBase&&) = default; + + template + auto CreateVarNode(const TGroup& group) -> decltype(auto) + { + using REACT_IMPL::PrivateReactiveGroupInterface; + using VarNodeType = REACT_IMPL::VarSignalNode; + + return std::make_shared(PrivateReactiveGroupInterface::GraphPtr(group)); + } + template auto CreateVarNode(T&& value, const TGroup& group) -> decltype(auto) { using REACT_IMPL::PrivateReactiveGroupInterface; - using VarNodeType = REACT_IMPL::VarSignalNode; return std::make_shared(PrivateReactiveGroupInterface::GraphPtr(group), std::forward(value)); @@ -174,9 +179,10 @@ class Signal : public SignalBase Signal(Signal&&) = default; Signal& operator=(Signal&&) = default; - template - Signal(F&& func, const SignalBase& ... deps) : - SignalBase( CreateFuncNode(std::forward(func), deps ...) ) + // Construct func signal + template + Signal(F&& func, const SignalBase& ... deps) : + Signal::SignalBase( CreateFuncNode(std::forward(func), deps ...) ) { } }; @@ -196,17 +202,20 @@ class Signal : public SignalBase Signal(Signal&&) = default; Signal& operator=(Signal&&) = default; + // Construct func signal + template + Signal(F&& func, const SignalBase& ... deps) : + Signal::SignalBase( CreateFuncNode(std::forward(func), deps ...) ) + { } + + // Construct from unique Signal(Signal&& other) : Signal::SignalBase( std::move(other) ) { } + // Assign from unique Signal& operator=(Signal&& other) { Signal::SignalBase::operator=(std::move(other)); return *this; } - - template - Signal(F&& func, const SignalBase& ... deps) : - Signal::SignalBase( CreateFuncNode(std::forward(func), deps ...) ) - { } }; /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -228,6 +237,13 @@ class VarSignal : public VarSignalBase VarSignal(VarSignal&&) = default; VarSignal& operator=(VarSignal&&) = default; + // Construct with default + template + explicit VarSignal(const TGroup& group) : + VarSignal::VarSignalBase( CreateVarNode( group) ) + { } + + // Construct with value template VarSignal(T&& value, const TGroup& group) : VarSignal::VarSignalBase( CreateVarNode(std::forward(value), group) ) @@ -250,13 +266,22 @@ class VarSignal : public VarSignalBase VarSignal(VarSignal&&) = default; VarSignal& operator=(VarSignal&&) = default; + // Construct from unique VarSignal(VarSignal&& other) : VarSignal::VarSignalBase( std::move(other) ) { } + // Assign from unique VarSignal& operator=(VarSignal&& other) { VarSignal::SignalBase::operator=(std::move(other)); return *this; } + // Construct with default + template + explicit VarSignal(const TGroup& group) : + VarSignal::VarSignalBase( CreateVarNode( group) ) + { } + + // Construct with value template VarSignal(T&& value, const TGroup& group) : VarSignal::VarSignalBase( CreateVarNode(std::forward(value), group) ) diff --git a/include/react/detail/EngineBase.h b/include/react/detail/EngineBase.h deleted file mode 100644 index 501c9c26..00000000 --- a/include/react/detail/EngineBase.h +++ /dev/null @@ -1,49 +0,0 @@ - -// Copyright Sebastian Jeckel 2016. -// 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) - -#ifndef REACT_DETAIL_ENGINEBASE_H_INCLUDED -#define REACT_DETAIL_ENGINEBASE_H_INCLUDED - -#pragma once - -#include "react/detail/Defs.h" - -#include -#include -#include -#include -#include - -#include "tbb/queuing_mutex.h" - -#include "react/common/Concurrency.h" -#include "react/common/Types.h" -#include "react/detail/ReactiveInput.h" -#include "react/detail/IReactiveNode.h" -#include "react/detail/IReactiveEngine.h" -#include "react/detail/ObserverBase.h" - -/***************************************/ REACT_IMPL_BEGIN /**************************************/ - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// TurnBase -/////////////////////////////////////////////////////////////////////////////////////////////////// -class TurnBase -{ -public: - inline TurnBase(TurnIdT id, TransactionFlagsT flags) : - id_( id ) - {} - - inline TurnIdT Id() const { return id_; } - -private: - TurnIdT id_; -}; - -/****************************************/ REACT_IMPL_END /***************************************/ - -#endif // REACT_DETAIL_ENGINEBASE_H_INCLUDED \ No newline at end of file diff --git a/include/react/detail/ObserverBase.h b/include/react/detail/ObserverBase.h deleted file mode 100644 index 6653ff04..00000000 --- a/include/react/detail/ObserverBase.h +++ /dev/null @@ -1,77 +0,0 @@ - -// Copyright Sebastian Jeckel 2016. -// 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) - -#ifndef REACT_DETAIL_OBSERVERBASE_H_INCLUDED -#define REACT_DETAIL_OBSERVERBASE_H_INCLUDED - -#pragma once - -#include "react/detail/Defs.h" - -#include -#include -#include - -/***************************************/ REACT_IMPL_BEGIN /**************************************/ - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// IObserver -/////////////////////////////////////////////////////////////////////////////////////////////////// -class IObserver -{ -public: - virtual ~IObserver() {} - - virtual void UnregisterSelf() = 0; - -private: - virtual void detachObserver() = 0; - - template - friend class Observable; -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Observable -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -class Observable -{ -public: - Observable() = default; - - ~Observable() - { - for (const auto& p : observers_) - if (p != nullptr) - p->detachObserver(); - } - - void RegisterObserver(std::unique_ptr&& obsPtr) - { - observers_.push_back(std::move(obsPtr)); - } - - void UnregisterObserver(IObserver* rawObsPtr) - { - for (auto it = observers_.begin(); it != observers_.end(); ++it) - { - if (it->get() == rawObsPtr) - { - it->get()->detachObserver(); - observers_.erase(it); - break; - } - } - } - -private: - std::vector> observers_; -}; - -/****************************************/ REACT_IMPL_END /***************************************/ - -#endif // REACT_DETAIL_OBSERVERBASE_H_INCLUDED \ No newline at end of file diff --git a/include/react/detail/graph/EventNodes.h b/include/react/detail/graph/EventNodes.h index 124636fc..bd966944 100644 --- a/include/react/detail/graph/EventNodes.h +++ b/include/react/detail/graph/EventNodes.h @@ -99,7 +99,8 @@ class EventStreamNode : public NodeBase //}); } - explicit EventStreamNode(const std::shared_ptr& graphPtr) : NodeBase( graphPtr ) + explicit EventStreamNode(const std::shared_ptr& graphPtr) : + NodeBase( graphPtr ) { } StorageType& Events() @@ -122,7 +123,8 @@ template class EventSourceNode : public EventStreamNode { public: - EventSourceNode(const std::shared_ptr& graphPtr) : EventSourceNode::EventStreamNode( graphPtr ) + EventSourceNode(const std::shared_ptr& graphPtr) : + EventSourceNode::EventStreamNode( graphPtr ) { this->RegisterMe(); } ~EventSourceNode() diff --git a/include/react/detail/graph/GraphBase.h b/include/react/detail/graph/GraphBase.h index 43d091da..b694e34e 100644 --- a/include/react/detail/graph/GraphBase.h +++ b/include/react/detail/graph/GraphBase.h @@ -18,7 +18,6 @@ #include "react/common/Types.h" #include "react/common/Util.h" #include "react/detail/IReactiveGraph.h" -#include "react/detail/ObserverBase.h" /***************************************/ REACT_IMPL_BEGIN /**************************************/ @@ -30,7 +29,8 @@ struct IReactiveGraph; class NodeBase : public IReactiveNode { public: - NodeBase(const std::shared_ptr& graphPtr) : graphPtr_( graphPtr ) + NodeBase(const std::shared_ptr& graphPtr) : + graphPtr_( graphPtr ) { } NodeBase(const NodeBase&) = delete; diff --git a/include/react/detail/graph/ObserverNodes.h b/include/react/detail/graph/ObserverNodes.h index b90e118e..0713c157 100644 --- a/include/react/detail/graph/ObserverNodes.h +++ b/include/react/detail/graph/ObserverNodes.h @@ -23,27 +23,22 @@ /////////////////////////////////////////////////////////////////////////////////////////////////// /// Forward declarations /////////////////////////////////////////////////////////////////////////////////////////////////// -template +template class SignalNode; -template +template class EventStreamNode; /////////////////////////////////////////////////////////////////////////////////////////////////// -/// ObserverNode +/// SignalObserverNode /////////////////////////////////////////////////////////////////////////////////////////////////// -class ObserverNode : public NodeBase, public IObserver +class ObserverNode : public NodeBase { public: - ObserverNode(IReactiveGraph* group) : NodeBase( group ) + ObserverNode(const std::shared_ptr& graphPtr) : + ObserverNode::NodeBase( graphPtr ) { } - ObserverNode(ObserverNode&&) = default; - ObserverNode& operator=(ObserverNode&&) = default; - - ObserverNode(const ObserverNode&) = delete; - ObserverNode& operator=(const ObserverNode&) = delete; - virtual bool IsOutputNode() const { return true; } }; @@ -51,56 +46,56 @@ class ObserverNode : public NodeBase, public IObserver /////////////////////////////////////////////////////////////////////////////////////////////////// /// SignalObserverNode /////////////////////////////////////////////////////////////////////////////////////////////////// -template +template class SignalObserverNode : public ObserverNode { public: template - SignalObserverNode(IReactiveGraph* group, const std::shared_ptr>& subject, FIn&& func) : - SignalObserverNode::ObserverNode( group ), - subject_( subject ), - func_( std::forward(func) ) + SignalObserverNode(const std::shared_ptr& graphPtr, FIn&& func, const std::shared_ptr>& ... deps) : + SignalObserverNode::ObserverNode( graphPtr ), + func_( std::forward(func) ), + depHolder_( deps ... ) { this->RegisterMe(); - this->AttachToMe(subject->GetNodeId()); + REACT_EXPAND_PACK(this->AttachToMe(deps->GetNodeId())); } ~SignalObserverNode() { - this->DetachFromMe(subject->GetNodeId()); + apply([this] (const auto& ... deps) { REACT_EXPAND_PACK(this->DetachFromMe(deps->GetNodeId())); }, depHolder_); this->UnregisterMe(); } virtual const char* GetNodeType() const override { return "SignalObserver"; } - virtual int DependencyCount() const override - { return 1; } + virtual int GetDependencyCount() const override + { return sizeof...(TDeps); } virtual UpdateResult Update(TurnId turnId) override { - func_(subject_->Value()); + apply([this] (const auto& ... deps) { this->func_(deps->Value() ...); }, depHolder_); return UpdateResult::unchanged; } private: - std::shared_ptr> subject_; - F func_; + + std::tuple> ...> depHolder_; }; /////////////////////////////////////////////////////////////////////////////////////////////////// /// EventObserverNode /////////////////////////////////////////////////////////////////////////////////////////////////// -template +template class EventObserverNode : public ObserverNode { public: template - EventObserverNode(IReactiveGraph* group, const std::shared_ptr>& subject, FIn&& func) : - EventObserverNode::ObserverNode( group ), - subject_( subject ), - func_( std::forward(func) ) + EventObserverNode(const std::shared_ptr& graphPtr, FIn&& func, const std::shared_ptr>& subject) : + EventObserverNode::ObserverNode( graphPtr ), + func_( std::forward(func) ), + subject_( subject ) { this->RegisterMe(); this->AttachToMe(subject->GetNodeId()); @@ -108,40 +103,40 @@ class EventObserverNode : public ObserverNode ~EventObserverNode() { - this->DetachFromMe(subject->GetNodeId()); + this->DetachFromMe(subject_->GetNodeId()); this->UnregisterMe(); } virtual const char* GetNodeType() const override - { return "EventObserverNode"; } + { return "EventObserver"; } - virtual int DependencyCount() const override + virtual int GetDependencyCount() const override { return 1; } virtual UpdateResult Update(TurnId turnId) override { - func_(EventRange( subject_->Events() )); + func_(EventRange( subject_->Events() )); return UpdateResult::unchanged; } private: - std::shared_ptr> subject_; - F func_; + + std::shared_ptr> subject_; }; /////////////////////////////////////////////////////////////////////////////////////////////////// -/// SyncedObserverNode +/// SyncedEventObserverNode /////////////////////////////////////////////////////////////////////////////////////////////////// -template -class SyncedObserverNode : public ObserverNode +template +class SyncedEventObserverNode : public ObserverNode { public: template - SyncedObserverNode(IReactiveGraph* group, const std::shared_ptr>& subject, FIn&& func, const std::shared_ptr>& ... syncs) : - SyncedObserverNode::ObserverNode( group ), - subject_( subject ), + SyncedEventObserverNode(const std::shared_ptr& graphPtr, FIn&& func, const std::shared_ptr>& subject, const std::shared_ptr>& ... syncs) : + SyncedEventObserverNode::ObserverNode( graphPtr ), func_( std::forward(func) ), + subject_( subject ), syncHolder_( syncs ... ) { this->RegisterMe(); @@ -149,7 +144,7 @@ class SyncedObserverNode : public ObserverNode REACT_EXPAND_PACK(this->AttachToMe(syncs->GetNodeId())); } - ~SyncedObserverNode() + ~SyncedEventObserverNode() { apply([this] (const auto& ... syncs) { REACT_EXPAND_PACK(this->DetachFromMe(syncs->GetNodeId())); }, syncHolder_); this->DetachFromMe(subject_->GetNodeId()); @@ -157,32 +152,26 @@ class SyncedObserverNode : public ObserverNode } virtual const char* GetNodeType() const override - { return "SyncedObserverNode"; } + { return "SyncedEventObserver"; } - virtual int DependencyCount() const override + virtual int GetDependencyCount() const override { return 1 + sizeof...(TSyncs); } virtual UpdateResult Update(TurnId turnId) override { // Update of this node could be triggered from deps, // so make sure source doesnt contain events from last turn - p->SetCurrentTurn(turnId); - - shouldDetach = apply( - [this] (const auto& ... syncs) - { - func_(EventRange( this->subject_->Events() ), syncs->Value() ...); - }, - syncHolder_); + subject_->SetCurrentTurn(turnId); + apply([this] (const auto& ... syncs) { func_(EventRange( this->subject_->Events() ), syncs->Value() ...); }, syncHolder_); return UpdateResult::unchanged; } private: - std::shared_ptr> subject_; - F func_; + std::shared_ptr> subject_; + std::tuple>...> syncHolder_; }; diff --git a/include/react/detail/graph/SignalNodes.h b/include/react/detail/graph/SignalNodes.h index b926ffa1..d45366e1 100644 --- a/include/react/detail/graph/SignalNodes.h +++ b/include/react/detail/graph/SignalNodes.h @@ -27,7 +27,7 @@ bool Equals(const L& lhs, const R& rhs); /////////////////////////////////////////////////////////////////////////////////////////////////// /// SignalNode /////////////////////////////////////////////////////////////////////////////////////////////////// -template +template class SignalNode : public NodeBase { public: @@ -37,29 +37,39 @@ class SignalNode : public NodeBase SignalNode(const SignalNode&) = delete; SignalNode& operator=(const SignalNode&) = delete; - template - SignalNode(const std::shared_ptr& graphPtr, U&& value) : + explicit SignalNode(const std::shared_ptr& graphPtr) : + SignalNode::NodeBase( graphPtr ), + value_( ) + { } + + template + SignalNode(const std::shared_ptr& graphPtr, T&& value) : SignalNode::NodeBase( graphPtr ), value_( std::forward(value) ) { } - T& Value() + S& Value() { return value_; } - const T& Value() const + const S& Value() const { return value_; } private: - T value_; + S value_; }; /////////////////////////////////////////////////////////////////////////////////////////////////// /// VarNode /////////////////////////////////////////////////////////////////////////////////////////////////// -template -class VarSignalNode : public SignalNode +template +class VarSignalNode : public SignalNode { public: + explicit VarSignalNode(const std::shared_ptr& graphPtr) : + VarSignalNode::SignalNode( graphPtr ), + newValue_( ) + { this->RegisterMe(); } + template VarSignalNode(const std::shared_ptr& graphPtr, T&& value) : VarSignalNode::SignalNode( graphPtr, std::forward(value) ), @@ -84,7 +94,7 @@ class VarSignalNode : public SignalNode { isInputAdded_ = false; - if (! Equals(this->Value(), newValue_)) + if (! (this->Value() == newValue_)) { this->Value() = std::move(newValue_); return UpdateResult::changed; @@ -106,10 +116,10 @@ class VarSignalNode : public SignalNode } } - template - void SetValue(U&& newValue) + template + void SetValue(T&& newValue) { - newValue_ = std::forward(newValue); + newValue_ = std::forward(newValue); isInputAdded_ = true; @@ -139,7 +149,7 @@ class VarSignalNode : public SignalNode } private: - T newValue_; + S newValue_; bool isInputAdded_ = false; bool isInputModified_ = false; }; @@ -147,14 +157,14 @@ class VarSignalNode : public SignalNode /////////////////////////////////////////////////////////////////////////////////////////////////// /// SignalOpNode /////////////////////////////////////////////////////////////////////////////////////////////////// -template -class SignalFuncNode : public SignalNode +template +class SignalFuncNode : public SignalNode { public: - template - SignalFuncNode(const std::shared_ptr& graphPtr, U&& func, const std::shared_ptr>& ... deps) : + template + SignalFuncNode(const std::shared_ptr& graphPtr, FIn&& func, const std::shared_ptr>& ... deps) : SignalFuncNode::SignalNode( graphPtr, func(deps->Value() ...) ), - func_( std::forward(func) ), + func_( std::forward(func) ), depHolder_( deps ... ) { this->RegisterMe(); @@ -167,13 +177,19 @@ class SignalFuncNode : public SignalNode this->UnregisterMe(); } + virtual const char* GetNodeType() const override + { return "SignalFunc"; } + + virtual int GetDependencyCount() const override + { return sizeof...(TDeps); } + virtual UpdateResult Update(TurnId turnId) override { bool changed = false; - T newValue = apply([this] (const auto& ... deps) { return this->func_(deps->Value() ...); }, depHolder_); + S newValue = apply([this] (const auto& ... deps) { return this->func_(deps->Value() ...); }, depHolder_); - if (! Equals(this->Value(), newValue)) + if (! (this->Value() == newValue)) { this->Value() = std::move(newValue); changed = true; @@ -185,16 +201,10 @@ class SignalFuncNode : public SignalNode return UpdateResult::unchanged; } - virtual const char* GetNodeType() const override - { return "SignalFunc"; } - - virtual int GetDependencyCount() const override - { return sizeof...(TDeps); } - private: - std::tuple> ...> depHolder_; - F func_; + + std::tuple> ...> depHolder_; }; /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -221,6 +231,15 @@ class SignalFlattenNode : public SignalNode this->UnregisterMe(); } + virtual const char* GetNodeType() const override + { return "SignalFlatten"; } + + virtual bool IsDynamicNode() const override + { return true; } + + virtual int GetDependencyCount() const override + { return 2; } + virtual UpdateResult Update(TurnId turnId) override { auto newInner = GetNodePtr(outer_->Value()); @@ -248,15 +267,6 @@ class SignalFlattenNode : public SignalNode } } - virtual const char* GetNodeType() const override - { return "SignalFlatten"; } - - virtual bool IsDynamicNode() const override - { return true; } - - virtual int GetDependencyCount() const override - { return 2; } - private: std::shared_ptr> outer_; std::shared_ptr> inner_; diff --git a/project/msvc/CppReact.vcxproj b/project/msvc/CppReact.vcxproj index 0d380c1c..7ef4b0dc 100644 --- a/project/msvc/CppReact.vcxproj +++ b/project/msvc/CppReact.vcxproj @@ -160,10 +160,8 @@ - - diff --git a/project/msvc/CppReact.vcxproj.filters b/project/msvc/CppReact.vcxproj.filters index 1174c9b1..c5384429 100644 --- a/project/msvc/CppReact.vcxproj.filters +++ b/project/msvc/CppReact.vcxproj.filters @@ -54,9 +54,6 @@ Header Files\detail - - Header Files\detail - Header Files\detail\graph @@ -66,9 +63,6 @@ Header Files\detail - - Header Files\detail - Header Files\detail\graph From 5114927925c60319f3830ef8d9c8540fc4a162a9 Mon Sep 17 00:00:00 2001 From: schlangster Date: Sun, 7 Aug 2016 23:26:12 +0200 Subject: [PATCH 33/75] Redesign WIP. Removed reactor stuff. Fixed basic examples. Observers, algorithms. Event buffer clearing. --- examples/CMakeLists.txt | 12 - examples/src/BasicAlgorithms.cpp | 238 +++++++++--------- examples/src/BasicEvents.cpp | 188 +++++++------- examples/src/BasicObservers.cpp | 142 ++--------- examples/src/BasicReactors.cpp | 161 ------------ examples/src/BasicSignals.cpp | 4 +- include/react/API.h | 12 +- include/react/Algorithm.h | 142 +++-------- include/react/Event.h | 26 +- include/react/Group.h | 3 +- include/react/Signal.h | 18 +- include/react/common/Util.h | 6 + include/react/detail/IReactiveGraph.h | 34 +-- include/react/detail/graph/AlgorithmNodes.h | 88 ++++--- include/react/detail/graph/EventNodes.h | 79 ++---- include/react/detail/graph/GraphBase.h | 13 +- include/react/detail/graph/ObserverNodes.h | 10 +- include/react/detail/graph/PropagationST.h | 45 +++- include/react/detail/graph/SignalNodes.h | 13 +- project/msvc/CppReact.sln | 15 +- project/msvc/Example_BasicReactors.vcxproj | 3 - .../Example_BasicReactors.vcxproj.filters | 5 - 22 files changed, 421 insertions(+), 836 deletions(-) delete mode 100644 examples/src/BasicReactors.cpp diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 940479ae..417819a0 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -14,18 +14,6 @@ target_link_libraries(Example_BasicEvents CppReact) add_executable(Example_BasicObservers src/BasicObservers.cpp) target_link_libraries(Example_BasicObservers CppReact) -### Example_BasicReactors -find_package(Boost 1.55 COMPONENTS coroutine context system) -if(Boost_FOUND) - include_directories(${Boost_INCLUDE_DIRS}) - add_executable(Example_BasicReactors src/BasicReactors.cpp) - target_link_libraries(Example_BasicReactors CppReact ${Boost_LIBRARIES}) -else() - message("boost::coroutine not found. Skipping build of Example_BasicReactors.") -endif() -#add_exyecutable(Example_BasicReactors src/BasicReactors.cpp) -#target_link_libraries(Example_BasicReactors CppReact) - ### Example_BasicSignals add_executable(Example_BasicSignals src/BasicSignals.cpp) target_link_libraries(Example_BasicSignals CppReact) diff --git a/examples/src/BasicAlgorithms.cpp b/examples/src/BasicAlgorithms.cpp index dd20b7bc..1e84305d 100644 --- a/examples/src/BasicAlgorithms.cpp +++ b/examples/src/BasicAlgorithms.cpp @@ -9,7 +9,6 @@ #include #include -#include "react/Domain.h" #include "react/Signal.h" #include "react/Event.h" #include "react/Observer.h" @@ -23,15 +22,12 @@ namespace example1 using namespace std; using namespace react; - REACTIVE_DOMAIN(D, sequential) + ReactiveGroup<> group; - class Sensor + struct Sensor { - public: - USING_REACTIVE_DOMAIN(D) - - EventSourceT Samples = MakeEventSource(); - SignalT LastSample = Hold(Samples, 0); + EventSource samples { group }; + Signal lastSample = Hold(0, samples); }; void Run() @@ -40,14 +36,18 @@ namespace example1 Sensor mySensor; - Observe(mySensor.LastSample, [] (int v) { - std::cout << v << std::endl; - }); + Observer<> obs( + [] (int v) + { + cout << v << endl; + }, + mySensor.lastSample); - mySensor.Samples << 20 << 21 << 21 << 22; // output: 20, 21, 22 + mySensor.samples << 20 << 21 << 21 << 22; // output: 20, 21, 22 - DoTransaction([&] { - mySensor.Samples << 30 << 31 << 31 << 32; + group.DoTransaction([&] + { + mySensor.samples << 30 << 31 << 31 << 32; }); // output: 32 cout << endl; @@ -62,17 +62,12 @@ namespace example2 using namespace std; using namespace react; - REACTIVE_DOMAIN(D, sequential) + ReactiveGroup<> group; - class Employee + struct Employee { - public: - USING_REACTIVE_DOMAIN(D) - - VarSignalT Name = MakeVar(string( "Bob" )); - VarSignalT Salary = MakeVar(3000); - - EventsT SalaryChanged = Monitor(Salary); + VarSignal name { string( "Bob" ), group }; + VarSignal salary { 3000, group }; }; void Run() @@ -81,12 +76,13 @@ namespace example2 Employee bob; - Observe( - bob.SalaryChanged, - With(bob.Name), - [] (int newSalary, const string& name) { - cout << name << " now earns " << newSalary << endl; - }); + Observer<> obs( + [] (EventRange in, const string& name) + { + for (int newSalary : in) + cout << name << " now earns " << newSalary << endl; + }, + Monitor(bob.salary), bob.name); cout << endl; } @@ -100,21 +96,21 @@ namespace example3 using namespace std; using namespace react; - REACTIVE_DOMAIN(D, sequential) + ReactiveGroup<> group; - class Counter + struct Counter { - public: - USING_REACTIVE_DOMAIN(D) + EventSource<> increment { group }; - EventSourceT<> Increment = MakeEventSource(); - - SignalT Count = Iterate( - Increment, + Signal count = Iterate( 0, - [] (Token, int oldCount) { - return oldCount + 1; - }); + [] (EventRange<> in, int count) + { + for (auto _ : in) + ++count; + return count; + }, + increment); }; void Run() @@ -123,12 +119,11 @@ namespace example3 Counter myCounter; - // Note: Using function-style operator() instead of .Emit() and .Value() - myCounter.Increment(); - myCounter.Increment(); - myCounter.Increment(); + myCounter.increment.Emit(); + myCounter.increment.Emit(); + myCounter.increment.Emit(); - cout << myCounter.Count() << endl; // output: 3 + cout << myCounter.count.Value() << endl; // output: 3 cout << endl; } @@ -142,34 +137,33 @@ namespace example4 using namespace std; using namespace react; - REACTIVE_DOMAIN(D, sequential) + ReactiveGroup<> group; - class Sensor + struct Sensor { - public: - USING_REACTIVE_DOMAIN(D) - - EventSourceT Input = MakeEventSource(); + EventSource input{ group }; - SignalT Count = Iterate( - Tokenize(Input), + Signal count = Iterate( 0, - [] (Token, int oldCount) { - return oldCount + 1; - }); - - SignalT Sum = Iterate( - Input, + [] (EventRange in, int count) + { + for (auto _ : in) + count++; + return count; + }, + input); + + Signal sum = Iterate( 0.0f, - [] (float v, float sum) { - return v + sum; - }); - - SignalT Average = MakeSignal( - With(Sum,Count), - [] (float sum, int count) { - return count != 0 ? sum / count : 0.0f; - }); + [] (EventRange in, float sum) + { + for (auto v : in) + sum += v; + return sum; + }, + input); + + VarSignal average{ group }; }; void Run() @@ -178,9 +172,9 @@ namespace example4 Sensor mySensor; - mySensor.Input << 10.0f << 5.0f << 10.0f << 8.0f; + mySensor.input << 10.0f << 5.0f << 10.0f << 8.0f; - cout << "Average: " << mySensor.Average() << endl; // output: 8.25 + cout << "Average: " << mySensor.average.Value() << endl; // output: 8.25 cout << endl; } @@ -194,31 +188,35 @@ namespace example5 using namespace std; using namespace react; - REACTIVE_DOMAIN(D, sequential) + ReactiveGroup<> group; enum ECmd { increment, decrement, reset }; class Counter { - public: - USING_REACTIVE_DOMAIN(D) - - EventSourceT Update = MakeEventSource(); - VarSignalT Delta = MakeVar(1); - VarSignalT Start = MakeVar(0); - - SignalT Count = Iterate( - Update, - Start.Value(), - With(Delta, Start), - [] (int cmd, int oldCount, int delta, int start) { + private: + static int DoCounterLoop(EventRange in, int count, int delta, int start) + { + for (int cmd : in) + { if (cmd == increment) - return oldCount + delta; + count += delta; else if (cmd == decrement) - return oldCount - delta; + count -= delta; else - return start; - }); + count = start; + } + + return count; + } + + public: + EventSource update{ group }; + + VarSignal delta{ 1, group }; + VarSignal start{ 0, group }; + + Signal count{ Iterate(start.Value(), DoCounterLoop, update, delta, start) }; }; void Run() @@ -227,23 +225,23 @@ namespace example5 Counter myCounter; - cout << "Start: " << myCounter.Count() << endl; // output: 0 + cout << "Start: " << myCounter.count.Value() << endl; // output: 0 - myCounter.Update(increment); - myCounter.Update(increment); - myCounter.Update(increment); + myCounter.update.Emit(increment); + myCounter.update.Emit(increment); + myCounter.update.Emit(increment); - cout << "3x increment by 1: " << myCounter.Count() << endl; // output: 3 + cout << "3x increment by 1: " << myCounter.count.Value() << endl; // output: 3 - myCounter.Delta <<= 5; - myCounter.Update(decrement); + myCounter.delta <<= 5; + myCounter.update.Emit(decrement); - cout << "1x decrement by 5: " << myCounter.Count() << endl; // output: -2 + cout << "1x decrement by 5: " << myCounter.count.Value() << endl; // output: -2 - myCounter.Start <<= 100; - myCounter.Update(reset); + myCounter.start <<= 100; + myCounter.update.Emit(reset); - cout << "reset to 100: " << myCounter.Count() << endl; // output: 100 + cout << "reset to 100: " << myCounter.count.Value() << endl; // output: 100 cout << endl; } @@ -257,32 +255,32 @@ namespace example6 using namespace std; using namespace react; - REACTIVE_DOMAIN(D, sequential) + ReactiveGroup<> group; class Sensor { - public: - USING_REACTIVE_DOMAIN(D) - - EventSourceT Input = MakeEventSource(); - - VarSignalT Threshold = MakeVar(42); - - SignalT> AllSamples = Iterate( - Input, - vector{}, - [] (int input, vector& all) { + private: + static void DoIterateAllSamples(EventRange in, vector& all) + { + for (int input : in) all.push_back(input); - }); + } - SignalT> CriticalSamples = Iterate( - Input, - vector{}, - With(Threshold), - [] (int input, vector& critical, int threshold) { + static void DoIterateCritSamples(EventRange in, vector& critical, int threshold) + { + for (int input : in) if (input > threshold) critical.push_back(input); - }); + } + + public: + EventSource input{ group }; + + VarSignal threshold{ 42, group }; + + Signal> allSamples{ Iterate>(vector{ }, DoIterateAllSamples, input) }; + + Signal> criticalSamples{ Iterate>(vector{ }, DoIterateCritSamples, input, threshold) }; }; void Run() @@ -291,15 +289,15 @@ namespace example6 Sensor mySensor; - mySensor.Input << 40 << 29 << 43 << 50; + mySensor.input << 40 << 29 << 43 << 50; cout << "All samples: "; - for (auto const& v : mySensor.AllSamples()) + for (auto const& v : mySensor.allSamples.Value()) cout << v << " "; cout << endl; cout << "Critical samples: "; - for (auto const& v : mySensor.CriticalSamples()) + for (auto const& v : mySensor.criticalSamples.Value()) cout << v << " "; cout << endl; diff --git a/examples/src/BasicEvents.cpp b/examples/src/BasicEvents.cpp index 0db396c3..b9a7cfbd 100644 --- a/examples/src/BasicEvents.cpp +++ b/examples/src/BasicEvents.cpp @@ -8,7 +8,6 @@ #include #include -#include "react/Domain.h" #include "react/Event.h" #include "react/Observer.h" @@ -20,36 +19,33 @@ 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 EventSourceT instead of D::EventSourceT. - USING_REACTIVE_DOMAIN(D) + // Defines a group. + // Each group represents a separate dependency graph. + // Reactives from different groups can not be mixed. + ReactiveGroup<> group; // An event source that emits values of type string namespace v1 { - EventSourceT mySource = MakeEventSource(); + EventSource mySource( group ); void Run() { cout << "Example 1 - Hello world (string source)" << endl; - Observe(mySource, [] (const string& s) { - std::cout << s << std::endl; - }); + Observer<> obs( + [] (EventRange in) + { + for (const auto& s : in) + cout << s << std::endl; + }, + mySource); mySource << string("Hello world #1"); // Or without the operator: mySource.Emit(string("Hello world #2")); - // Or as a function call: - mySource(string("Hello world #3")); - cout << endl; } } @@ -57,7 +53,7 @@ namespace example1 // An event source without an explicit value type namespace v2 { - EventSourceT<> helloWorldTrigger = MakeEventSource(); + EventSource<> helloWorldTrigger( group ); void Run() { @@ -65,18 +61,19 @@ namespace example1 int count = 0; - Observe(helloWorldTrigger, [&] (Token) { - cout << "Hello world #" << ++count << endl; - }); + Observer<> obs( + [&] (EventRange<> in) + { + for (auto t : in) + cout << "Hello world #" << ++count << endl; + }, + helloWorldTrigger); helloWorldTrigger.Emit(); // Or without the stream operator: helloWorldTrigger << Token::value; - // Or as a function call: - helloWorldTrigger(); - cout << endl; } } @@ -90,57 +87,32 @@ namespace example2 using namespace std; using namespace react; - REACTIVE_DOMAIN(D, sequential) - USING_REACTIVE_DOMAIN(D) + ReactiveGroup<> group; // An event stream that merges both sources - namespace v1 - { - EventSourceT<> leftClick = MakeEventSource(); - EventSourceT<> rightClick = MakeEventSource(); - - EventsT<> anyClick = Merge(leftClick, rightClick); - - void Run() - { - cout << "Example 2 - Merging event streams (Merge)" << endl; + EventSource<> leftClick( group ); + EventSource<> rightClick( group ); - int count = 0; - - Observe(anyClick, [&] (Token) { - cout << "clicked #" << ++count << endl; - }); - - leftClick.Emit(); // output: clicked #1 - rightClick.Emit(); // output: clicked #2 + Event<> anyClick = Merge(leftClick, rightClick); - cout << endl; - } - } - - // Using overloaded operator | instead of explicit Merge - namespace v2 + void Run() { - EventSourceT<> leftClick = MakeEventSource(); - EventSourceT<> rightClick = MakeEventSource(); + cout << "Example 2 - Merging event streams (Merge)" << endl; - EventsT<> anyClick = leftClick | rightClick; + int count = 0; - void Run() - { - cout << "Example 2 - Merging event streams (operator)" << endl; - - int count = 0; - - Observe(anyClick, [&] (Token) { - cout << "clicked #" << ++count << endl; - }); + Observer<> obs( + [&] (EventRange<> in) + { + for (auto t : in) + cout << "clicked #" << ++count << endl; + }, + anyClick); - leftClick.Emit(); // output: clicked #1 - rightClick.Emit(); // output: clicked #2 + leftClick.Emit(); // output: clicked #1 + rightClick.Emit(); // output: clicked #2 - cout << endl; - } + cout << endl; } } @@ -152,22 +124,23 @@ namespace example3 using namespace std; using namespace react; - REACTIVE_DOMAIN(D, sequential) - USING_REACTIVE_DOMAIN(D) + ReactiveGroup<> group; - EventSourceT numbers = MakeEventSource(); + EventSource numbers( group ); - EventsT greater10 = Filter(numbers, [] (int n) { - return n > 10; - }); + Event greater10 = Filter([] (int n) { return n > 10; }, numbers); void Run() { cout << "Example 3 - Filtering events" << endl; - Observe(greater10, [] (int n) { - cout << n << endl; - }); + Observer<> obs( + [&] (EventRange in) + { + for (auto n : in) + cout << n << endl; + }, + greater10); numbers << 5 << 11 << 7 << 100; // output: 11, 100 @@ -183,32 +156,40 @@ namespace example4 using namespace std; using namespace react; - REACTIVE_DOMAIN(D, sequential) - USING_REACTIVE_DOMAIN(D) + ReactiveGroup<> group; // Data types - enum class ETag { normal, critical }; - using TaggedNum = pair; + enum class Tag { normal, critical }; + using TaggedNum = pair; - EventSourceT numbers = MakeEventSource(); + EventSource numbers( group ); - EventsT tagged = Transform(numbers, [] (int n) { - if (n > 10) - return TaggedNum( ETag::critical, n ); - else - return TaggedNum( ETag::normal, n ); - }); + Event tagged = Transform( + [] (int n) + { + if (n > 10) + return TaggedNum( Tag::critical, n ); + else + return TaggedNum( Tag::normal, n ); + }, + numbers); void Run() { cout << "Example 4 - Transforming events" << endl; - Observe(tagged, [] (const TaggedNum& t) { - if (t.first == ETag::critical) - cout << "(critical) " << t.second << endl; - else - cout << "(normal) " << t.second << endl; - }); + Observer<> obs( + [] (EventRange in) + { + for (TaggedNum e : in) + { + if (e.first == Tag::critical) + cout << "(critical) " << e.second << endl; + else + cout << "(normal) " << e.second << endl; + } + }, + tagged); numbers << 5; // output: (normal) 5 numbers << 20; // output: (critical) 20 @@ -225,20 +206,24 @@ namespace example5 using namespace std; using namespace react; - REACTIVE_DOMAIN(D, sequential) - USING_REACTIVE_DOMAIN(D) + ReactiveGroup<> group; - EventSourceT src = MakeEventSource(); + EventSource src( group ); void Run() { cout << "Example 5 - Queuing multiple inputs" << endl; - Observe(src, [] (int v) { - cout << v << endl; - }); // output: 1, 2, 3, 4 + Observer<> obs( + [] (EventRange in) + { + for (int e : in) + cout << e << endl; + }, src); + // output: 1, 2, 3, 4 - DoTransaction([] { + group.DoTransaction([] + { src << 1 << 2 << 3; src << 4; }); @@ -254,14 +239,9 @@ int main() { example1::v1::Run(); example1::v2::Run(); - - example2::v1::Run(); - example2::v2::Run(); - + example2::Run(); example3::Run(); - example4::Run(); - example5::Run(); return 0; diff --git a/examples/src/BasicObservers.cpp b/examples/src/BasicObservers.cpp index 2c1b911e..0a282528 100644 --- a/examples/src/BasicObservers.cpp +++ b/examples/src/BasicObservers.cpp @@ -8,7 +8,6 @@ #include #include -#include "react/Domain.h" #include "react/Signal.h" #include "react/Event.h" #include "react/Observer.h" @@ -21,77 +20,25 @@ namespace example1 using namespace std; using namespace react; - REACTIVE_DOMAIN(D, sequential) - USING_REACTIVE_DOMAIN(D) + ReactiveGroup<> group; - auto x = MakeVar(1); + VarSignal x( 1, group ); - namespace v1 + void Run() { - void Run() - { - cout << "Example 1 - Creating subject-bound observers (v1)" << endl; - - { - // Create a signal in the function scope - auto mySignal = MakeSignal(x, [] (int x) { return x; } ); - - // The lifetime of the observer is bound to mySignal. - // After Run() returns, mySignal is destroyed, and so is the observer - Observe(mySignal, [] (int mySignal) { - cout << mySignal << endl; - }); - - x <<= 2; // output: 2 - } + cout << "Example 1 - Creating subject-bound observers (v1)" << endl; - x <<= 3; // no ouput - - cout << endl; - } - } - - namespace v2 - { - void Run() { - cout << "Example 1 - Creating subject-bound observers (v2)" << endl; - - // Outer scope - { - // Unbound observer - ObserverT obs; - - // Inner scope - { - auto mySignal = MakeSignal(x, [] (int x) { return x; } ); - - // Move-assign to obs - obs = Observe(mySignal, [] (int mySignal) { - cout << mySignal << endl; - }); - - // The node linked to mySignal is now also owned by obs - - x <<= 2; // output: 2 - } - // ~Inner scope - - // mySignal was destroyed, but as long as obs exists and is still - // attached to the signal node, this signal node won't be destroyed + Signal mySignal( [] (int x) { return x; }, x ); - x <<= 3; // output: 3 - } - // ~Outer scope + Observer<> obs( [] (int mySignal) { cout << mySignal << endl; }, mySignal ); - // obs was destroyed - // -> the signal node is no longer owned by anything and is destroyed - // -> the observer node is destroyed as it was bound to the subject + x <<= 2; // output: 2 + } - x <<= 4; // no ouput + x <<= 3; // no ouput - cout << endl; - } + cout << endl; } } @@ -103,71 +50,28 @@ namespace example2 using namespace std; using namespace react; - REACTIVE_DOMAIN(D, sequential) - USING_REACTIVE_DOMAIN(D) + ReactiveGroup<> group; - EventSourceT<> trigger = MakeEventSource(); + EventSource<> trigger( group ); void Run() { cout << "Example 2 - Detaching observers manually" << endl; - ObserverT obs = Observe(trigger, [] (Token) { - cout << "Triggered!" << endl; - }); + Observer<> obs( + [] (EventRange<> in) + { + for (auto _ : in) + cout << "Triggered!" << endl; + }, + trigger); trigger.Emit(); // output: Triggered! - obs.Detach(); // Remove the observer - - trigger.Emit(); // no output - - cout << endl; - } -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Example 3 - Using scoped observers -/////////////////////////////////////////////////////////////////////////////////////////////////// -namespace example3 -{ - using namespace std; - using namespace react; - - REACTIVE_DOMAIN(D, sequential) - USING_REACTIVE_DOMAIN(D) - - EventSourceT<> trigger = MakeEventSource(); - - void Run() - { - cout << "Example 3 - Using scoped observers" << endl; - - // Inner scope - { - ScopedObserverT scopedObs - ( - Observe(trigger, [] (Token) { - cout << "Triggered!" << endl; - }) - ); - - trigger.Emit(); // output: Triggered! - } - // ~Inner scope + obs.Cancel(); // Remove the observer trigger.Emit(); // no output - // Note the semantic difference between ScopedObserverT and ObserverT. - // - // During its lifetime, the ObserverT handle of an observer guarantees that the - // observed subject will not be destroyed and allows explicit detach. - // But even after the ObserverT handle is destroyed, the subject may continue to exist - // and so will the observer. - // - // ScopedObserverT has similar semantics to a scoped lock. - // When it's destroyed, it detaches and destroys the observer. - cout << endl; } } @@ -177,12 +81,8 @@ namespace example3 /////////////////////////////////////////////////////////////////////////////////////////////////// int main() { - example1::v1::Run(); - example1::v2::Run(); - + example1::Run(); example2::Run(); - example3::Run(); - return 0; } \ No newline at end of file diff --git a/examples/src/BasicReactors.cpp b/examples/src/BasicReactors.cpp deleted file mode 100644 index 534c1346..00000000 --- a/examples/src/BasicReactors.cpp +++ /dev/null @@ -1,161 +0,0 @@ - -// Copyright Sebastian Jeckel 2016. -// 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 "react/Domain.h" -#include "react/Signal.h" -#include "react/Event.h" -#include "react/Reactor.h" - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Example 1 - Creating reactive loops -/////////////////////////////////////////////////////////////////////////////////////////////////// -namespace example1 -{ - using namespace std; - using namespace react; - - REACTIVE_DOMAIN(D, sequential) - USING_REACTIVE_DOMAIN(D) - - using PointT = pair; - using PathT = vector; - - vector paths; - - EventSourceT mouseDown = MakeEventSource(); - EventSourceT mouseUp = MakeEventSource(); - EventSourceT mouseMove = MakeEventSource(); - - ReactorT loop - { - [&] (ReactorT::Context ctx) - { - PathT points; - - points.emplace_back(ctx.Await(mouseDown)); - - ctx.RepeatUntil(mouseUp, [&] { - points.emplace_back(ctx.Await(mouseMove)); - }); - - points.emplace_back(ctx.Await(mouseUp)); - - paths.push_back(points); - } - }; - - void Run() - { - cout << "Example 1 - Creating reactive loops" << endl; - - mouseDown << PointT( 1,1 ); - mouseMove << PointT( 2,2 ) << PointT( 3,3 ) << PointT( 4,4 ); - mouseUp << PointT( 5,5 ); - - mouseMove << PointT( 999,999 ); - - mouseDown << PointT( 10,10 ); - mouseMove << PointT( 20,20 ); - mouseUp << PointT( 30,30 ); - - for (const auto& path : paths) - { - cout << "Path: "; - for (const auto& point : path) - cout << "(" << point.first << "," << point.second << ") "; - cout << endl; - } - - cout << endl; - } -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Example 2 - Creating reactive loops -/////////////////////////////////////////////////////////////////////////////////////////////////// -namespace example2 -{ - using namespace std; - using namespace react; - - REACTIVE_DOMAIN(D, sequential) - USING_REACTIVE_DOMAIN(D) - - using PointT = pair; - using PathT = vector; - - vector paths; - - EventSourceT mouseDown = MakeEventSource(); - EventSourceT mouseUp = MakeEventSource(); - EventSourceT mouseMove = MakeEventSource(); - - VarSignalT counter = MakeVar(103); - - ReactorT loop - { - [&] (ReactorT::Context ctx) - { - PathT points; - - points.emplace_back(ctx.Await(mouseDown)); - - auto count = ctx.Get(counter); - - ctx.RepeatUntil(mouseUp, [&] { - points.emplace_back(ctx.Await(mouseMove)); - }); - - points.emplace_back(ctx.Await(mouseUp)); - - paths.push_back(points); - } - }; - - void Run() - { - cout << "Example 2 - Creating reactive loops" << endl; - - mouseDown << PointT( 1,1 ); - mouseMove << PointT( 2,2 ) << PointT( 3,3 ) << PointT( 4,4 ); - mouseUp << PointT( 5,5 ); - - counter <<= 42; - - mouseMove << PointT( 999,999 ); - - counter <<= 80; - - mouseDown << PointT( 10,10 ); - mouseMove << PointT( 20,20 ); - mouseUp << PointT( 30,30 ); - - for (const auto& path : paths) - { - cout << "Path: "; - for (const auto& point : path) - cout << "(" << point.first << "," << point.second << ") "; - cout << endl; - } - - cout << endl; - } -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Run examples -/////////////////////////////////////////////////////////////////////////////////////////////////// -int main() -{ - example1::Run(); - example2::Run(); - - return 0; -} \ No newline at end of file diff --git a/examples/src/BasicSignals.cpp b/examples/src/BasicSignals.cpp index bebdf7bf..3007d199 100644 --- a/examples/src/BasicSignals.cpp +++ b/examples/src/BasicSignals.cpp @@ -27,8 +27,8 @@ namespace example1 { return first + string(" ") + second; } // Defines a group. - // Each domain represents a separate dependency graph, managed by a dedicated propagation engine. - // Reactives of different domains can not be combined. + // Each group represents a separate dependency graph. + // Reactives from different groups can not be mixed. ReactiveGroup<> group; // The two words diff --git a/include/react/API.h b/include/react/API.h index 68b6f531..435e6562 100644 --- a/include/react/API.h +++ b/include/react/API.h @@ -72,19 +72,21 @@ template class VarSignal; // Events -template +enum class Token; + +template class EventBase; -template +template class EventSourceBase; -template +template class Event; -template +template class EventSource; -enum class Token; + // Observers template diff --git a/include/react/Algorithm.h b/include/react/Algorithm.h index e6624d74..af6bce46 100644 --- a/include/react/Algorithm.h +++ b/include/react/Algorithm.h @@ -28,9 +28,10 @@ auto Hold(T&& initialValue, const EventBase& events) -> Signal { using REACT_IMPL::HoldNode; using REACT_IMPL::PrivateNodeInterface; + using REACT_IMPL::NodeCtorTag; - return Signal( std::make_shared>( - PrivateNodeInterface::GraphPtr(events), std::forward(initialValue), PrivateNodeInterface::NodePtr(events)) ); + return Signal( NodeCtorTag{ }, std::make_shared>( + PrivateNodeInterface::GraphPtr(events), std::forward(initialValue), PrivateNodeInterface::NodePtr(events)) ); } /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -41,8 +42,9 @@ auto Monitor(const SignalBase& signal) -> Event { using REACT_IMPL::MonitorNode; using REACT_IMPL::PrivateNodeInterface; + using REACT_IMPL::NodeCtorTag; - return Event( std::make_shared>( + return Event( NodeCtorTag{ }, std::make_shared>( PrivateNodeInterface::GraphPtr(signal), PrivateNodeInterface::NodePtr(signal)) ); } @@ -50,121 +52,46 @@ auto Monitor(const SignalBase& signal) -> Event /// Iterate - Iteratively combines signal value with values from event stream (aka Fold) /////////////////////////////////////////////////////////////////////////////////////////////////// template -auto Iterate(T&& init, F&& func, const Events& events) -> Signal +auto Iterate(T&& init, F&& func, const EventBase& events) -> Signal { using REACT_IMPL::IterateNode; using REACT_IMPL::IterateByRefNode; - using REACT_IMPL::AddIterateRangeWrapper; - using REACT_IMPL::AddIterateByRefRangeWrapper; using REACT_IMPL::IsCallableWith; - using REACT_IMPL::EventRange; - - using TFunc = typename std::decay::type; - - using NodeT = - typename std::conditional< - IsCallableWith,S>::value, - IterateNode, - typename std::conditional< - IsCallableWith::value, - IterateNode>, - typename std::conditional< - IsCallableWith, S&>::value, - IterateByRefNode, - typename std::conditional< - IsCallableWith::value, - IterateByRefNode>, - void - >::type - >::type - >::type - >::type; - - static_assert( - ! std::is_same::value, - "Iterate: Passed function does not match any of the supported signatures."); - - return Signal( - std::make_shared( - std::forward(init), GetNodePtr(events), std::forward(func))); + using REACT_IMPL::PrivateNodeInterface; + using REACT_IMPL::NodeCtorTag; + + using FuncType = typename std::decay::type; + using IterNodeType = typename std::conditional< + IsCallableWith,S>::value, + IterateNode, + IterateByRefNode>::type; + + return Signal( NodeCtorTag{ }, std::make_shared( + PrivateNodeInterface::GraphPtr(events), std::forward(init), std::forward(func), PrivateNodeInterface::NodePtr(events) )); } /////////////////////////////////////////////////////////////////////////////////////////////////// /// Iterate - Synced /////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename S, - typename E, - typename V, - typename FIn, - typename ... TDepValues -> -auto Iterate(const Events& events, V&& init, const SignalPack& depPack, FIn&& func) -> Signal +template +auto Iterate(T&& init, F&& func, const EventBase& events, const SignalBase& ... signals) -> Signal { using REACT_IMPL::SyncedIterateNode; using REACT_IMPL::SyncedIterateByRefNode; - using REACT_IMPL::AddIterateRangeWrapper; - using REACT_IMPL::AddIterateByRefRangeWrapper; using REACT_IMPL::IsCallableWith; - using REACT_IMPL::EventRange; - - using F = typename std::decay::type; - - using NodeT = - typename std::conditional< - IsCallableWith,S,TDepValues ...>::value, - SyncedIterateNode, - typename std::conditional< - IsCallableWith::value, - SyncedIterateNode, - TDepValues ...>, - typename std::conditional< - IsCallableWith,S&,TDepValues ...>::value, - SyncedIterateByRefNode, - typename std::conditional< - IsCallableWith::value, - SyncedIterateByRefNode, - TDepValues ...>, - void - >::type - >::type - >::type - >::type; - - static_assert( - ! std::is_same::value, - "Iterate: Passed function does not match any of the supported signatures."); - - //static_assert(NodeT::dummy_error, "DUMP MY TYPE" ); - - struct NodeBuilder_ - { - NodeBuilder_(const Events& source, V&& init, FIn&& func) : - MySource( source ), - MyInit( std::forward(init) ), - MyFunc( std::forward(func) ) - {} - - auto operator()(const Signal& ... deps) - -> Signal - { - return Signal( - std::make_shared( - std::forward(MyInit), GetNodePtr(MySource), - std::forward(MyFunc), GetNodePtr(deps) ...)); - } - - const Events& MySource; - V MyInit; - FIn MyFunc; - }; - - return REACT_IMPL::apply( - NodeBuilder_( events, std::forward(init), std::forward(func) ), - depPack.Data); + using REACT_IMPL::GetCheckedGraphPtr; + using REACT_IMPL::PrivateNodeInterface; + using REACT_IMPL::NodeCtorTag; + + using FuncType = typename std::decay::type; + using IterNodeType = typename std::conditional< + IsCallableWith, S, Us ...>::value, + SyncedIterateNode, + SyncedIterateByRefNode>::type; + + return Signal( NodeCtorTag{ }, std::make_shared( + GetCheckedGraphPtr(events, signals ...), + std::forward(init), std::forward(func), PrivateNodeInterface::NodePtr(events), PrivateNodeInterface::NodePtr(signals) ...)); } /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -176,8 +103,9 @@ auto Snapshot(const SignalBase& signal, const EventBase& trigger) -> Signa using REACT_IMPL::SnapshotNode; using REACT_IMPL::GetCheckedGraphPtr; using REACT_IMPL::PrivateNodeInterface; + using REACT_IMPL::NodeCtorTag; - return Events( std::make_shared>( + return Events( NodeCtorTag{ }, std::make_shared>( GetCheckedGraphPtr(signal, trigger), PrivateNodeInterface::NodePtr(signal), PrivateNodeInterface::NodePtr(trigger)) ); } @@ -191,7 +119,7 @@ auto Pulse(const SignalBase& signal, const EventBase& trigger) -> Event( std::make_shared>( + return Event( NodeCtorTag{ }, std::make_shared>( GetCheckedGraphPtr(signal, trigger), PrivateNodeInterface::NodePtr(signal), PrivateNodeInterface::NodePtr(trigger)) ); } diff --git a/include/react/Event.h b/include/react/Event.h index 637268ff..13fdcb5c 100644 --- a/include/react/Event.h +++ b/include/react/Event.h @@ -31,8 +31,8 @@ class EventBase using NodeType = REACT_IMPL::EventStreamNode; public: - // Node ctor - explicit EventBase(std::shared_ptr&& nodePtr) : + // Private node ctor + EventBase(REACT_IMPL::NodeCtorTag, std::shared_ptr&& nodePtr) : nodePtr_( std::move(nodePtr) ) { } @@ -176,12 +176,12 @@ class Event : public EventBase template Event(F&& func, const EventBase& dep) : - Event::EventBase( CreateProcessingNode(std::forward(func), dep) ) + Event::EventBase( REACT_IMPL::NodeCtorTag{ }, CreateProcessingNode(std::forward(func), dep) ) { } template Event(F&& func, const EventBase& dep, const SignalBase& ... signals) : - Event::EventBase( CreateSyncedProcessingNode(std::forward(func), dep, signals ...) ) + Event::EventBase( REACT_IMPL::NodeCtorTag{ }, CreateSyncedProcessingNode(std::forward(func), dep, signals ...) ) { } }; @@ -210,12 +210,12 @@ class Event : public EventBase template Event(F&& func, const EventBase& dep) : - Event::EventBase( CreateProcessingNode(std::forward(func), dep) ) + Event::EventBase( REACT_IMPL::NodeCtorTag{ }, CreateProcessingNode(std::forward(func), dep) ) { } template Event(F&& func, const EventBase& dep, const SignalBase& ... signals) : - Event::EventBase( SyncedCreateProcessingNode(std::forward(func), dep, signals ...) ) + Event::EventBase( REACT_IMPL::NodeCtorTag{ }, CreateSyncedProcessingNode(std::forward(func), dep, signals ...) ) { } }; @@ -241,7 +241,7 @@ class EventSource : public EventSourceBase // Construct event source template explicit EventSource(const TGroup& group) : - EventSource::EventSourceBase( CreateSourceNode(group) ) + EventSource::EventSourceBase( REACT_IMPL::NodeCtorTag{ }, CreateSourceNode(group) ) { } }; @@ -264,7 +264,7 @@ class EventSource : public EventSourceBase // Construct event source template explicit EventSource(const TGroup& group) : - EventSource::EventSourceBase( CreateSourceNode(group) ) + EventSource::EventSourceBase( REACT_IMPL::NodeCtorTag{ }, CreateSourceNode(group) ) { } // Construct from unique @@ -286,6 +286,7 @@ auto Merge(const EventBase& dep1, const EventBase& ... deps) -> decltype using REACT_IMPL::EventMergeNode; using REACT_IMPL::GetCheckedGraphPtr; using REACT_IMPL::PrivateNodeInterface; + using REACT_IMPL::NodeCtorTag; static_assert(sizeof...(Us) > 0, "Merge requires at least 2 inputs."); @@ -297,8 +298,8 @@ auto Merge(const EventBase& dep1, const EventBase& ... deps) -> decltype const auto& graphPtr = GetCheckedGraphPtr(dep1, deps ...); - return Event( - std::make_shared>(graphPtr, PrivateNodeInterface::NodePtr(dep1), PrivateNodeInterface::NodePtr(deps) ...)); + return Event( NodeCtorTag{ }, std::make_shared>( + graphPtr, PrivateNodeInterface::NodePtr(dep1), PrivateNodeInterface::NodePtr(deps) ...)); } /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -370,14 +371,15 @@ auto Join(const EventBase& ... deps) -> Event, unique> using REACT_IMPL::EventJoinNode; using REACT_IMPL::GetCheckedGraphPtr; using REACT_IMPL::PrivateNodeInterface; + using REACT_IMPL::NodeCtorTag; static_assert(sizeof...(Ts) > 1, "Join requires at least 2 inputs."); // If supplied, use merge type, otherwise default to common type. const auto& graphPtr = GetCheckedGraphPtr(deps ...); - return Event, unique>( - std::make_shared>(graphPtr, PrivateNodeInterface::NodePtr(deps) ...)); + return Event, unique>( NodeCtorTag{ }, std::make_shared>( + graphPtr, PrivateNodeInterface::NodePtr(deps) ...)); } /////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/include/react/Group.h b/include/react/Group.h index 71434d1e..c8324d1c 100644 --- a/include/react/Group.h +++ b/include/react/Group.h @@ -15,8 +15,6 @@ #include #include "react/API.h" -#include "react/Signal.h" -//#include "react/Event.h" #include "react/detail/IReactiveGraph.h" #include "react/detail/graph/PropagationST.h" @@ -25,6 +23,7 @@ struct PrivateReactiveGroupInterface; struct PrivateConcurrentReactiveGroupInterface; +struct NodeCtorTag { }; /****************************************/ REACT_IMPL_END /***************************************/ diff --git a/include/react/Signal.h b/include/react/Signal.h index c46a0b94..22e4e548 100644 --- a/include/react/Signal.h +++ b/include/react/Signal.h @@ -37,7 +37,7 @@ class SignalBase public: // Private node ctor - explicit SignalBase(std::shared_ptr&& nodePtr) : + SignalBase(REACT_IMPL::NodeCtorTag, std::shared_ptr&& nodePtr) : nodePtr_( std::move(nodePtr) ) { } @@ -181,8 +181,8 @@ class Signal : public SignalBase // Construct func signal template - Signal(F&& func, const SignalBase& ... deps) : - Signal::SignalBase( CreateFuncNode(std::forward(func), deps ...) ) + explicit Signal(F&& func, const SignalBase& ... deps) : + Signal::SignalBase( REACT_IMPL::NodeCtorTag{ }, CreateFuncNode(std::forward(func), deps ...) ) { } }; @@ -204,8 +204,8 @@ class Signal : public SignalBase // Construct func signal template - Signal(F&& func, const SignalBase& ... deps) : - Signal::SignalBase( CreateFuncNode(std::forward(func), deps ...) ) + explicit Signal(F&& func, const SignalBase& ... deps) : + Signal::SignalBase( REACT_IMPL::NodeCtorTag{ }, CreateFuncNode(std::forward(func), deps ...) ) { } // Construct from unique @@ -240,13 +240,13 @@ class VarSignal : public VarSignalBase // Construct with default template explicit VarSignal(const TGroup& group) : - VarSignal::VarSignalBase( CreateVarNode( group) ) + VarSignal::VarSignalBase( REACT_IMPL::NodeCtorTag{ }, CreateVarNode( group) ) { } // Construct with value template VarSignal(T&& value, const TGroup& group) : - VarSignal::VarSignalBase( CreateVarNode(std::forward(value), group) ) + VarSignal::VarSignalBase( REACT_IMPL::NodeCtorTag{ }, CreateVarNode(std::forward(value), group) ) { } }; @@ -278,13 +278,13 @@ class VarSignal : public VarSignalBase // Construct with default template explicit VarSignal(const TGroup& group) : - VarSignal::VarSignalBase( CreateVarNode( group) ) + VarSignal::VarSignalBase( REACT_IMPL::NodeCtorTag{ }, CreateVarNode( group) ) { } // Construct with value template VarSignal(T&& value, const TGroup& group) : - VarSignal::VarSignalBase( CreateVarNode(std::forward(value), group) ) + VarSignal::VarSignalBase( REACT_IMPL::NodeCtorTag{ }, CreateVarNode(std::forward(value), group) ) { } }; diff --git a/include/react/common/Util.h b/include/react/common/Util.h index 741cd61d..4721723d 100644 --- a/include/react/common/Util.h +++ b/include/react/common/Util.h @@ -216,6 +216,12 @@ class IsCallableWith static const bool value = sizeof(check(nullptr)) == sizeof(YesT); }; +template +bool IsBitmaskSet(T flags, T mask) +{ + return (flags & mask) != (T)0; +} + /****************************************/ REACT_IMPL_END /***************************************/ // Expand args by wrapping them in a dummy function diff --git a/include/react/detail/IReactiveGraph.h b/include/react/detail/IReactiveGraph.h index ddb29689..4cf87bf0 100644 --- a/include/react/detail/IReactiveGraph.h +++ b/include/react/detail/IReactiveGraph.h @@ -37,6 +37,16 @@ enum class UpdateResult shifted }; +enum class NodeFlags +{ + none, + input, + output, + dynamic, + buffered +}; +REACT_DEFINE_BITMASK_OPERATORS(NodeFlags) + struct IReactiveGraph; struct IReactiveNode; @@ -47,7 +57,7 @@ struct IReactiveGraph { virtual ~IReactiveGraph() = default; - virtual NodeId RegisterNode(IReactiveNode* nodePtr) = 0; + virtual NodeId RegisterNode(IReactiveNode* nodePtr, NodeFlags flags) = 0; virtual void UnregisterNode(NodeId node) = 0; virtual void OnNodeAttach(NodeId nodeId, NodeId parentId) = 0; @@ -66,33 +76,13 @@ struct IReactiveNode { virtual ~IReactiveNode() = default; - /// Returns unique type identifier virtual const char* GetNodeType() const = 0; - // Note: Could get rid of this ugly ptr by adding a template parameter to the interface - // But that would mean all engine nodes need that template parameter too - so rather cast virtual UpdateResult Update(TurnId turnId) = 0; - /// Input nodes can be manipulated externally. - virtual bool IsInputNode() const = 0; - - /// Output nodes can't have any successors. - virtual bool IsOutputNode() const = 0; - - /// Dynamic nodes may change in topology as a result of tick. - virtual bool IsDynamicNode() const = 0; - - // Number of predecessors. virtual int GetDependencyCount() const = 0; -}; -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// EPropagationMode -/////////////////////////////////////////////////////////////////////////////////////////////////// -enum EPropagationMode -{ - sequential_propagation, - parallel_propagation + virtual void ClearBuffer() = 0; }; /****************************************/ REACT_IMPL_END /***************************************/ diff --git a/include/react/detail/graph/AlgorithmNodes.h b/include/react/detail/graph/AlgorithmNodes.h index e3b8d584..6d696532 100644 --- a/include/react/detail/graph/AlgorithmNodes.h +++ b/include/react/detail/graph/AlgorithmNodes.h @@ -81,15 +81,15 @@ struct AddIterateByRefRangeWrapper /////////////////////////////////////////////////////////////////////////////////////////////////// /// IterateNode /////////////////////////////////////////////////////////////////////////////////////////////////// -template +template class IterateNode : public SignalNode { public: - template - IterateNode(const std::shared_ptr& graphPtr, U&& init, const std::shared_ptr>& events, FIn&& func) : - IterateNode::SignalNode( graphPtr, std::forward(init) ), - events_( events ), - func_( std::forward(func) ) + template + IterateNode(const std::shared_ptr& graphPtr, T&& init, FIn&& func, const std::shared_ptr>& events) : + IterateNode::SignalNode( graphPtr, std::forward(init) ), + func_( std::forward(func) ), + events_( events ) { this->RegisterMe(); this->AttachToMe(events->GetNodeId()); @@ -105,7 +105,7 @@ class IterateNode : public SignalNode { S newValue = func_(EventRange( events_->Events() ), this->Value()); - if (! Equals(newValue, this->Value())) + if (! (newValue == this->Value())) { this->Value() = std::move(newValue); return UpdateResult::changed; @@ -125,19 +125,19 @@ class IterateNode : public SignalNode private: std::shared_ptr> events_; - F func_; + F func_; }; /////////////////////////////////////////////////////////////////////////////////////////////////// /// IterateByRefNode /////////////////////////////////////////////////////////////////////////////////////////////////// -template +template class IterateByRefNode : public SignalNode { public: - template - IterateByRefNode(const std::shared_ptr& graphPtr, SIn&& init, const std::shared_ptr>& events, FIn&& func) : - IterateByRefNode::SignalNode( graphPtr, std::forward(init) ), + template + IterateByRefNode(const std::shared_ptr& graphPtr, T&& init, FIn&& func, const std::shared_ptr>& events) : + IterateByRefNode::SignalNode( graphPtr, std::forward(init) ), func_( std::forward(func) ), events_( events ) { @@ -174,33 +174,31 @@ class IterateByRefNode : public SignalNode /////////////////////////////////////////////////////////////////////////////////////////////////// /// SyncedIterateNode /////////////////////////////////////////////////////////////////////////////////////////////////// -template +template class SyncedIterateNode : public SignalNode { public: - template - SyncedIterateNode(const std::shared_ptr& graphPtr, SIn&& init, const std::shared_ptr>& events, FIn&& func, const std::shared_ptr>& ... syncs) : - SyncedIterateNode::SignalNode( graphPtr, std::forward(init) ), - events_( events ), + template + SyncedIterateNode(const std::shared_ptr& graphPtr, T&& init, FIn&& func, const std::shared_ptr>& events, const std::shared_ptr>& ... syncs) : + SyncedIterateNode::SignalNode( graphPtr, std::forward(init) ), func_( std::forward(func) ), + events_( events ), syncHolder_( syncs ... ) { this->RegisterMe(); - this->AttachToMe(dep->GetNodeId()); + this->AttachToMe(events->GetNodeId()); REACT_EXPAND_PACK(this->AttachToMe(syncs->GetNodeId())); } ~SyncedIterateNode() { apply([this] (const auto& ... syncs) { REACT_EXPAND_PACK(this->DetachFromMe(syncs->GetNodeId())); }, syncHolder_); - this->DetachFromMe(dep_->GetNodeId()); + this->DetachFromMe(events_->GetNodeId()); this->UnregisterMe(); } virtual UpdateResult Update(TurnId turnId) override { - events_->SetCurrentTurn(turn); - S newValue = apply( [this] (const auto& ... syncs) { @@ -208,7 +206,7 @@ class SyncedIterateNode : public SignalNode }, syncHolder_); - if (! Equals(newValue, this->Value())) + if (! (newValue == this->Value())) { this->Value() = std::move(newValue); return UpdateResult::changed; @@ -226,42 +224,42 @@ class SyncedIterateNode : public SignalNode { return 1 + sizeof...(TSyncs); } private: - std::shared_ptr> events_; - F func_; + std::shared_ptr> events_; + std::tuple>...> syncHolder_; }; /////////////////////////////////////////////////////////////////////////////////////////////////// /// SyncedIterateByRefNode /////////////////////////////////////////////////////////////////////////////////////////////////// -template +template class SyncedIterateByRefNode : public SignalNode { public: - template - SyncedIterateByRefNode(const std::shared_ptr& graphPtr, SIn&& init, const std::shared_ptr>& events, FIn&& func, const std::shared_ptr>& ... syncs) : + template + SyncedIterateByRefNode(const std::shared_ptr& graphPtr, T&& init, FIn&& func, const std::shared_ptr>& events, const std::shared_ptr>& ... syncs) : SyncedIterateByRefNode::SignalNode( graphPtr, std::forward(init) ), - events_( events ), func_( std::forward(func) ), + events_( events ), syncHolder_( syncs ... ) { this->RegisterMe(); - this->AttachToMe(dep->GetNodeId()); + this->AttachToMe(events->GetNodeId()); REACT_EXPAND_PACK(this->AttachToMe(syncs->GetNodeId())); } ~SyncedIterateByRefNode() { apply([this] (const auto& ... syncs) { REACT_EXPAND_PACK(this->DetachFromMe(syncs->GetNodeId())); }, syncHolder_); - this->DetachFromMe(dep_->GetNodeId()); + this->DetachFromMe(events_->GetNodeId()); this->UnregisterMe(); } virtual UpdateResult Update(TurnId turnId) override { - events_->SetCurrentTurn(turn); + events_->SetCurrentTurn(turnId); bool changed = false; @@ -272,7 +270,7 @@ class SyncedIterateByRefNode : public SignalNode { func_(EventRange( events_->Events() ), this->Value(), args->Value() ...); }, - deps_); + syncHolder_); return UpdateResult::changed; } @@ -289,23 +287,23 @@ class SyncedIterateByRefNode : public SignalNode { return 1 + sizeof...(TSyncs); } private: - std::shared_ptr> events_; - F func_; + std::shared_ptr> events_; + std::tuple>...> syncHolder_; }; /////////////////////////////////////////////////////////////////////////////////////////////////// /// HoldNode /////////////////////////////////////////////////////////////////////////////////////////////////// -template -class HoldNode : public SignalNode +template +class HoldNode : public SignalNode { public: - template - HoldNode(const std::shared_ptr& graphPtr, TIn&& init, const std::shared_ptr>& events) : - HoldNode::SignalNode( graphPtr, std::forward(init) ), + template + HoldNode(const std::shared_ptr& graphPtr, T&& init, const std::shared_ptr>& events) : + HoldNode::SignalNode( graphPtr, std::forward(init) ), events_( events ) { this->RegisterMe(); @@ -329,7 +327,7 @@ class HoldNode : public SignalNode { const S& newValue = events_->Events().back(); - if (! Equals(newValue, this->Value())) + if (! (newValue == this->Value())) { changed = true; this->Value() = newValue; @@ -410,11 +408,11 @@ class SnapshotNode : public SignalNode /////////////////////////////////////////////////////////////////////////////////////////////////// /// MonitorNode /////////////////////////////////////////////////////////////////////////////////////////////////// -template -class MonitorNode : public EventStreamNode +template +class MonitorNode : public EventStreamNode { public: - MonitorNode(const std::shared_ptr& graphPtr, const std::shared_ptr>& target) : + MonitorNode(const std::shared_ptr& graphPtr, const std::shared_ptr>& target) : MonitorNode::EventStreamNode( graphPtr ), target_( target ) { @@ -430,7 +428,7 @@ class MonitorNode : public EventStreamNode virtual UpdateResult Update(TurnId turnId) override { - this->SetCurrentTurn(turn, true); + this->SetCurrentTurn(turnId, true); this->Events().push_back(target_->Value()); @@ -444,7 +442,7 @@ class MonitorNode : public EventStreamNode { return 1; } private: - std::shared_ptr> target_; + std::shared_ptr> target_; }; /////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/include/react/detail/graph/EventNodes.h b/include/react/detail/graph/EventNodes.h index bd966944..caf2e049 100644 --- a/include/react/detail/graph/EventNodes.h +++ b/include/react/detail/graph/EventNodes.h @@ -27,7 +27,7 @@ /////////////////////////////////////////////////////////////////////////////////////////////////// /// Iterators for event processing /////////////////////////////////////////////////////////////////////////////////////////////////// -template +template class EventRange { public: @@ -87,33 +87,21 @@ class EventStreamNode : public NodeBase EventStreamNode(const EventStreamNode&) = delete; EventStreamNode& operator=(const EventStreamNode&) = delete; - void SetCurrentTurn(TurnId turnId, bool forceUpdate = false, bool noClear = false) - { - //this->AccessBufferForClearing([&] { - // if (curTurnId_ != turn.Id() || forceUpdate) - // { - // curTurnId_ = turn.Id(); - // if (!noClear) - // events_.clear(); - // } - //}); - } - explicit EventStreamNode(const std::shared_ptr& graphPtr) : NodeBase( graphPtr ) { } - StorageType& Events() + StorageType& Events() { return events_; } - const StorageType& Events() const + const StorageType& Events() const { return events_; } -protected: - StorageType events_; + virtual void ClearBuffer() override + { events_.clear(); }; private: - uint curTurnId_ { (std::numeric_limits::max)() }; + StorageType events_; }; /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -125,7 +113,7 @@ class EventSourceNode : public EventStreamNode public: EventSourceNode(const std::shared_ptr& graphPtr) : EventSourceNode::EventStreamNode( graphPtr ) - { this->RegisterMe(); } + { this->RegisterMe(NodeFlags::buffered | NodeFlags::input); } ~EventSourceNode() { this->UnregisterMe(); } @@ -133,19 +121,13 @@ class EventSourceNode : public EventStreamNode virtual const char* GetNodeType() const override { return "EventSource"; } - virtual bool IsInputNode() const override - { return true; } - virtual int GetDependencyCount() const override { return 0; } virtual UpdateResult Update(TurnId turnId) override { - if (this->Events().size() > 0 && !changedFlag_) - { - this->SetCurrentTurn(turnId, true, true); - changedFlag_ = true; - + if (this->Events().size() > 0) + { return UpdateResult::changed; } else @@ -157,18 +139,8 @@ class EventSourceNode : public EventStreamNode template void EmitValue(U&& value) { - // Clear input from previous turn - if (changedFlag_) - { - changedFlag_ = false; - this->Events().clear(); - } - this->Events().push_back(std::forward(value)); } - -private: - bool changedFlag_ = false; }; /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -182,7 +154,7 @@ class EventMergeNode : public EventStreamNode EventMergeNode::EventStreamNode( graphPtr ), depHolder_( deps ... ) { - this->RegisterMe(); + this->RegisterMe(NodeFlags::buffered); REACT_EXPAND_PACK(this->AttachToMe(deps->GetNodeId())); } @@ -194,8 +166,6 @@ class EventMergeNode : public EventStreamNode virtual UpdateResult Update(TurnId turnId) override { - this->SetCurrentTurn(turnId, true); - apply([this] (const auto& ... deps) { REACT_EXPAND_PACK(MergeFromDep(deps)); }, depHolder_); if (! this->Events().empty()) @@ -214,7 +184,6 @@ class EventMergeNode : public EventStreamNode template void MergeFromDep(const std::shared_ptr>& other) { - //arg->SetCurrentTurn(turn); this->Events().insert(this->Events().end(), other->Events().begin(), other->Events().end()); } @@ -233,7 +202,7 @@ class EventFlattenNode : public EventStreamNode outer_( outer ), inner_( inner ) { - this->RegisterMe(); + this->RegisterMe(NodeFlags::buffered | NodeFlags::dynamic); this->AttachToMe(outer->GetNodeId()); this->AttachToMe(inner->GetNodeId()); } @@ -248,17 +217,11 @@ class EventFlattenNode : public EventStreamNode virtual const char* GetNodeType() const override { return "EventFlatten"; } - virtual bool IsDynamicNode() const override - { return true; } - virtual int GetDependencyCount() const override { return 2; } virtual UpdateResult Update(TurnId turnId) override { - this->SetCurrentTurn(turnId, true); - inner_->SetCurrentTurn(turnId); - auto newInner = GetNodePtr(outer_->Value()); if (newInner != inner_) @@ -301,7 +264,7 @@ class EventProcessingNode : public EventStreamNode func_( std::forward(func) ), dep_( dep ) { - this->RegisterMe(); + this->RegisterMe(NodeFlags::buffered); this->AttachToMe(dep->GetNodeId()); } @@ -313,8 +276,6 @@ class EventProcessingNode : public EventStreamNode virtual UpdateResult Update(TurnId turnId) override { - this->SetCurrentTurn(turnId, true); - func_(EventRange( dep_->Events() ), std::back_inserter(this->Events())); if (! this->Events().empty()) @@ -349,7 +310,7 @@ class SyncedEventProcessingNode : public EventStreamNode dep_( dep ), syncHolder_( syncs ... ) { - this->RegisterMe(); + this->RegisterMe(NodeFlags::buffered); this->AttachToMe(dep->GetNodeId()); REACT_EXPAND_PACK(this->AttachToMe(syncs->GetNodeId())); } @@ -363,10 +324,9 @@ class SyncedEventProcessingNode : public EventStreamNode virtual UpdateResult Update(TurnId turnId) override { - this->SetCurrentTurn(turnId, true); - // Update of this node could be triggered from deps, - // so make sure source doesnt contain events from last turn - dep_->SetCurrentTurn(turnId); + // Updates might be triggered even if only sync nodes changed. Ignore those. + if (dep_->Events().empty()) + return UpdateResult::unchanged; apply( [this] (const auto& ... syncs) @@ -406,7 +366,7 @@ class EventJoinNode : public EventStreamNode> EventJoinNode::EventStreamNode( graphPtr ), slots_( deps ... ) { - this->RegisterMe(); + this->RegisterMe(NodeFlags::buffered); REACT_EXPAND_PACK(this->AttachToMe(deps->GetNodeId())); } @@ -418,8 +378,6 @@ class EventJoinNode : public EventStreamNode> virtual UpdateResult Update(TurnId turnId) override { - this->SetCurrentTurn(turnId, true); - // Move events into buffers apply([this, turnId] (Slot& ... slots) { REACT_EXPAND_PACK(FetchBuffer(turnId, slots)); }, slots_); @@ -429,7 +387,7 @@ class EventJoinNode : public EventStreamNode> // All slots ready? apply( - [this,&isReady] (Slot& ... slots) { + [this, &isReady] (Slot& ... slots) { // Todo: combine return values instead REACT_EXPAND_PACK(CheckSlot(slots, isReady)); }, @@ -475,7 +433,6 @@ class EventJoinNode : public EventStreamNode> template static void FetchBuffer(TurnId turnId, Slot& slot) { - slot.source->SetCurrentTurn(turnId); slot.buffer.insert(slot.buffer.end(), slot.source->Events().begin(), slot.source->Events().end()); } diff --git a/include/react/detail/graph/GraphBase.h b/include/react/detail/graph/GraphBase.h index b694e34e..8466d77b 100644 --- a/include/react/detail/graph/GraphBase.h +++ b/include/react/detail/graph/GraphBase.h @@ -38,15 +38,6 @@ class NodeBase : public IReactiveNode NodeBase(NodeBase&&) = delete; NodeBase& operator=(NodeBase&&) = delete; - - virtual bool IsInputNode() const override - { return false; } - - virtual bool IsOutputNode() const override - { return false; } - - virtual bool IsDynamicNode() const override - { return false; } /*void SetWeightHint(WeightHint weight) { @@ -74,8 +65,8 @@ class NodeBase : public IReactiveNode { return graphPtr_; } protected: - void RegisterMe() - { nodeId_ = graphPtr_->RegisterNode(this); } + void RegisterMe(NodeFlags flags = NodeFlags::none) + { nodeId_ = graphPtr_->RegisterNode(this, flags); } void UnregisterMe() { graphPtr_->UnregisterNode(nodeId_); } diff --git a/include/react/detail/graph/ObserverNodes.h b/include/react/detail/graph/ObserverNodes.h index 0713c157..abdf1c6e 100644 --- a/include/react/detail/graph/ObserverNodes.h +++ b/include/react/detail/graph/ObserverNodes.h @@ -39,8 +39,8 @@ class ObserverNode : public NodeBase ObserverNode::NodeBase( graphPtr ) { } - virtual bool IsOutputNode() const - { return true; } + virtual void ClearBuffer() override + { }; }; /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -56,7 +56,7 @@ class SignalObserverNode : public ObserverNode func_( std::forward(func) ), depHolder_( deps ... ) { - this->RegisterMe(); + this->RegisterMe(NodeFlags::output); REACT_EXPAND_PACK(this->AttachToMe(deps->GetNodeId())); } @@ -97,7 +97,7 @@ class EventObserverNode : public ObserverNode func_( std::forward(func) ), subject_( subject ) { - this->RegisterMe(); + this->RegisterMe(NodeFlags::output); this->AttachToMe(subject->GetNodeId()); } @@ -139,7 +139,7 @@ class SyncedEventObserverNode : public ObserverNode subject_( subject ), syncHolder_( syncs ... ) { - this->RegisterMe(); + this->RegisterMe(NodeFlags::output); this->AttachToMe(subject->GetNodeId()); REACT_EXPAND_PACK(this->AttachToMe(syncs->GetNodeId())); } diff --git a/include/react/detail/graph/PropagationST.h b/include/react/detail/graph/PropagationST.h index bfbc0828..863df8e5 100644 --- a/include/react/detail/graph/PropagationST.h +++ b/include/react/detail/graph/PropagationST.h @@ -26,7 +26,7 @@ class SingleThreadedGraph : public IReactiveGraph { public: // IReactiveGraph - virtual NodeId RegisterNode(IReactiveNode* nodePtr) override; + virtual NodeId RegisterNode(IReactiveNode* nodePtr, NodeFlags flags) override; virtual void UnregisterNode(NodeId node) override; virtual void OnNodeAttach(NodeId node, NodeId parentId) override; @@ -49,15 +49,19 @@ class SingleThreadedGraph : public IReactiveGraph NodeData(const NodeData&) = default; NodeData& operator=(const NodeData&) = default; - NodeData(IReactiveNode* nodePtrIn) : - nodePtr( nodePtrIn ) + NodeData(IReactiveNode* nodePtrIn, NodeFlags flagsIn) : + nodePtr( nodePtrIn ), + flags( flagsIn ) { } + NodeFlags flags = NodeFlags::none; + int level = 0; int newLevel = 0 ; bool queued = false; IReactiveNode* nodePtr = nullptr; + std::vector successors; }; @@ -89,6 +93,7 @@ class SingleThreadedGraph : public IReactiveGraph void ScheduleSuccessors(NodeData & node); void InvalidateSuccessors(NodeData & node); + void ClearBufferedNodes(); private: int refCount_ = 1; @@ -97,12 +102,14 @@ class SingleThreadedGraph : public IReactiveGraph IndexMap nodeData_; std::vector changedInputs_; + std::vector pendingBufferedNodes_; + bool isTransactionActive_ = false; }; -NodeId SingleThreadedGraph::RegisterNode(IReactiveNode* nodePtr) +NodeId SingleThreadedGraph::RegisterNode(IReactiveNode* nodePtr, NodeFlags flags) { - return nodeData_.Insert(NodeData{ nodePtr }); + return nodeData_.Insert(NodeData{ nodePtr, flags }); } void SingleThreadedGraph::UnregisterNode(NodeId nodeId) @@ -159,12 +166,17 @@ void SingleThreadedGraph::AddInput(NodeId nodeId, std::function inputCal // Update the node. This applies the input buffer to the node value and checks if it changed. if (nodePtr->Update(0) == UpdateResult::changed) { + if (IsBitmaskSet(node.flags, NodeFlags::buffered)) + pendingBufferedNodes_.push_back(nodePtr); + // Propagate changes through the graph ScheduleSuccessors(node); if (! scheduledNodes_.IsEmpty()) Propagate(); - } + } + + ClearBufferedNodes(); } } @@ -180,9 +192,15 @@ void SingleThreadedGraph::DoTransaction(TransactionFlags flags, F&& transactionC for (NodeId nodeId : changedInputs_) { auto& node = nodeData_[nodeId]; + auto* nodePtr = node.nodePtr; + + if (nodePtr->Update(0) == UpdateResult::changed) + { + if (IsBitmaskSet(node.flags, NodeFlags::buffered)) + pendingBufferedNodes_.push_back(nodePtr); - if (node.nodePtr->Update(0) == UpdateResult::changed) ScheduleSuccessors(node); + } } changedInputs_.clear(); @@ -199,6 +217,7 @@ void SingleThreadedGraph::Propagate() for (NodeId nodeId : scheduledNodes_.Next()) { auto& node = nodeData_[nodeId]; + auto* nodePtr = node.nodePtr; if (node.level < node.newLevel) { @@ -209,10 +228,13 @@ void SingleThreadedGraph::Propagate() continue; } - auto result = node.nodePtr->Update(0); + auto result = nodePtr->Update(0); if (result == UpdateResult::changed) { + if (IsBitmaskSet(node.flags, NodeFlags::buffered)) + pendingBufferedNodes_.push_back(nodePtr); + ScheduleSuccessors(node); } else if (result == UpdateResult::shifted) @@ -253,6 +275,13 @@ void SingleThreadedGraph::InvalidateSuccessors(NodeData& node) } } +void SingleThreadedGraph::ClearBufferedNodes() +{ + for (IReactiveNode* nodePtr : pendingBufferedNodes_) + nodePtr->ClearBuffer(); + pendingBufferedNodes_.clear(); +} + bool SingleThreadedGraph::TopoQueue::FetchNext() { // Throw away previous values diff --git a/include/react/detail/graph/SignalNodes.h b/include/react/detail/graph/SignalNodes.h index d45366e1..30128a3e 100644 --- a/include/react/detail/graph/SignalNodes.h +++ b/include/react/detail/graph/SignalNodes.h @@ -54,6 +54,9 @@ class SignalNode : public NodeBase const S& Value() const { return value_; } + virtual void ClearBuffer() override + { }; + private: S value_; }; @@ -68,7 +71,7 @@ class VarSignalNode : public SignalNode explicit VarSignalNode(const std::shared_ptr& graphPtr) : VarSignalNode::SignalNode( graphPtr ), newValue_( ) - { this->RegisterMe(); } + { this->RegisterMe(NodeFlags::input); } template VarSignalNode(const std::shared_ptr& graphPtr, T&& value) : @@ -82,9 +85,6 @@ class VarSignalNode : public SignalNode virtual const char* GetNodeType() const override { return "VarSignal"; } - virtual bool IsInputNode() const override - { return true; } - virtual int GetDependencyCount() const override { return 0; } @@ -219,7 +219,7 @@ class SignalFlattenNode : public SignalNode outer_( outer ), inner_( inner ) { - this->RegisterMe(); + this->RegisterMe(NodeFlags::dynamic); this->AttachToMe(outer->GetNodeId()); this->AttachToMe(inner->GetNodeId()); } @@ -234,9 +234,6 @@ class SignalFlattenNode : public SignalNode virtual const char* GetNodeType() const override { return "SignalFlatten"; } - virtual bool IsDynamicNode() const override - { return true; } - virtual int GetDependencyCount() const override { return 2; } diff --git a/project/msvc/CppReact.sln b/project/msvc/CppReact.sln index b414852d..bd00b26a 100644 --- a/project/msvc/CppReact.sln +++ b/project/msvc/CppReact.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2013 -VisualStudioVersion = 12.0.30501.0 +# Visual Studio 14 +VisualStudioVersion = 14.0.25420.1 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CppReact", "CppReact.vcxproj", "{5E56AAB9-4E33-4B9E-A315-E85CEDB75CF1}" EndProject @@ -27,8 +27,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Example_BasicEvents", "Exam EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Example_BasicObservers", "Example_BasicObservers.vcxproj", "{CC66BFA0-D609-46E0-9FD1-F9CC902410B1}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Example_BasicReactors", "Example_BasicReactors.vcxproj", "{D976F4D4-B472-4709-BFB5-B1BEEA1F7E96}" -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Example_BasicSignals", "Example_BasicSignals.vcxproj", "{230C9137-CCD0-47E2-8F1F-2E1DD19984A1}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Example_BasicSynchronization", "Example_BasicSynchronization.vcxproj", "{269329F8-A9E1-41AC-9C37-3A82A082A62C}" @@ -105,14 +103,6 @@ Global {CC66BFA0-D609-46E0-9FD1-F9CC902410B1}.Release|Win32.Build.0 = Release|Win32 {CC66BFA0-D609-46E0-9FD1-F9CC902410B1}.Release|x64.ActiveCfg = Release|x64 {CC66BFA0-D609-46E0-9FD1-F9CC902410B1}.Release|x64.Build.0 = Release|x64 - {D976F4D4-B472-4709-BFB5-B1BEEA1F7E96}.Debug|Win32.ActiveCfg = Debug|Win32 - {D976F4D4-B472-4709-BFB5-B1BEEA1F7E96}.Debug|Win32.Build.0 = Debug|Win32 - {D976F4D4-B472-4709-BFB5-B1BEEA1F7E96}.Debug|x64.ActiveCfg = Debug|x64 - {D976F4D4-B472-4709-BFB5-B1BEEA1F7E96}.Debug|x64.Build.0 = Debug|x64 - {D976F4D4-B472-4709-BFB5-B1BEEA1F7E96}.Release|Win32.ActiveCfg = Release|Win32 - {D976F4D4-B472-4709-BFB5-B1BEEA1F7E96}.Release|Win32.Build.0 = Release|Win32 - {D976F4D4-B472-4709-BFB5-B1BEEA1F7E96}.Release|x64.ActiveCfg = Release|x64 - {D976F4D4-B472-4709-BFB5-B1BEEA1F7E96}.Release|x64.Build.0 = Release|x64 {230C9137-CCD0-47E2-8F1F-2E1DD19984A1}.Debug|Win32.ActiveCfg = Debug|Win32 {230C9137-CCD0-47E2-8F1F-2E1DD19984A1}.Debug|Win32.Build.0 = Debug|Win32 {230C9137-CCD0-47E2-8F1F-2E1DD19984A1}.Debug|x64.ActiveCfg = Debug|x64 @@ -142,7 +132,6 @@ Global {D7B70D3B-F14D-4A85-B164-EAB88C358E85} = {518ACABC-E4A7-4E2D-9A04-FFA669A30DBF} {BD777649-97F1-4810-BF21-CB27F7672BF4} = {518ACABC-E4A7-4E2D-9A04-FFA669A30DBF} {CC66BFA0-D609-46E0-9FD1-F9CC902410B1} = {518ACABC-E4A7-4E2D-9A04-FFA669A30DBF} - {D976F4D4-B472-4709-BFB5-B1BEEA1F7E96} = {518ACABC-E4A7-4E2D-9A04-FFA669A30DBF} {230C9137-CCD0-47E2-8F1F-2E1DD19984A1} = {518ACABC-E4A7-4E2D-9A04-FFA669A30DBF} {269329F8-A9E1-41AC-9C37-3A82A082A62C} = {518ACABC-E4A7-4E2D-9A04-FFA669A30DBF} EndGlobalSection diff --git a/project/msvc/Example_BasicReactors.vcxproj b/project/msvc/Example_BasicReactors.vcxproj index ba7b1dad..247db825 100644 --- a/project/msvc/Example_BasicReactors.vcxproj +++ b/project/msvc/Example_BasicReactors.vcxproj @@ -136,9 +136,6 @@ true - - - {5e56aab9-4e33-4b9e-a315-e85cedb75cf1} diff --git a/project/msvc/Example_BasicReactors.vcxproj.filters b/project/msvc/Example_BasicReactors.vcxproj.filters index 7398067f..6a1782f7 100644 --- a/project/msvc/Example_BasicReactors.vcxproj.filters +++ b/project/msvc/Example_BasicReactors.vcxproj.filters @@ -14,9 +14,4 @@ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - Source Files - - \ No newline at end of file From 1fc56425a7ea44b4cbbb618974ff2b1e76fe7d12 Mon Sep 17 00:00:00 2001 From: schlangster Date: Mon, 8 Aug 2016 23:25:30 +0200 Subject: [PATCH 34/75] Fixes. --- include/react/API.h | 2 +- include/react/detail/IReactiveGraph.h | 10 +++++----- include/react/detail/graph/AlgorithmNodes.h | 10 ++-------- include/react/detail/graph/PropagationST.h | 2 ++ 4 files changed, 10 insertions(+), 14 deletions(-) diff --git a/include/react/API.h b/include/react/API.h index 435e6562..dbbf88f9 100644 --- a/include/react/API.h +++ b/include/react/API.h @@ -44,7 +44,7 @@ enum class WeightHint enum class TransactionFlags { - none = 1 << 0, + none = 0, allow_merging = 1 << 1 }; diff --git a/include/react/detail/IReactiveGraph.h b/include/react/detail/IReactiveGraph.h index 4cf87bf0..e081844f 100644 --- a/include/react/detail/IReactiveGraph.h +++ b/include/react/detail/IReactiveGraph.h @@ -39,11 +39,11 @@ enum class UpdateResult enum class NodeFlags { - none, - input, - output, - dynamic, - buffered + none = 0, + input = 1 << 0, + output = 1 << 1, + dynamic = 1 << 2, + buffered = 1 << 3 }; REACT_DEFINE_BITMASK_OPERATORS(NodeFlags) diff --git a/include/react/detail/graph/AlgorithmNodes.h b/include/react/detail/graph/AlgorithmNodes.h index 6d696532..b5bb7aa6 100644 --- a/include/react/detail/graph/AlgorithmNodes.h +++ b/include/react/detail/graph/AlgorithmNodes.h @@ -416,7 +416,7 @@ class MonitorNode : public EventStreamNode MonitorNode::EventStreamNode( graphPtr ), target_( target ) { - this->RegisterMe(); + this->RegisterMe(NodeFlags::buffered); this->AttachToMe(target->GetNodeId()); } @@ -428,10 +428,7 @@ class MonitorNode : public EventStreamNode virtual UpdateResult Update(TurnId turnId) override { - this->SetCurrentTurn(turnId, true); - this->Events().push_back(target_->Value()); - return UpdateResult::changed; } @@ -457,7 +454,7 @@ class PulseNode : public EventStreamNode target_( target ), trigger_( trigger ) { - this->RegisterMe(); + this->RegisterMe(NodeFlags::buffered); this->AttachToMe(target->GetNodeId()); this->AttachToMe(trigger->GetNodeId()); } @@ -471,9 +468,6 @@ class PulseNode : public EventStreamNode virtual UpdateResult Update(TurnId turnId) override { - this->SetCurrentTurn(turn, true); - trigger_->SetCurrentTurn(turn); - for (size_t i=0; iEvents().size(); i++) this->Events().push_back(target_->Value()); diff --git a/include/react/detail/graph/PropagationST.h b/include/react/detail/graph/PropagationST.h index 863df8e5..96d4fee4 100644 --- a/include/react/detail/graph/PropagationST.h +++ b/include/react/detail/graph/PropagationST.h @@ -208,6 +208,8 @@ void SingleThreadedGraph::DoTransaction(TransactionFlags flags, F&& transactionC // Propagate changes through the graph. if (! scheduledNodes_.IsEmpty()) Propagate(); + + ClearBufferedNodes(); } void SingleThreadedGraph::Propagate() From 5a988398d629623ae6ace185c27974c001fd87a6 Mon Sep 17 00:00:00 2001 From: schlangster Date: Mon, 5 Sep 2016 23:02:30 +0200 Subject: [PATCH 35/75] Progress. SlotNodes. --- examples/src/BasicEvents.cpp | 38 ++- examples/src/BasicSignals.cpp | 36 ++- include/react/API.h | 20 +- include/react/Event.h | 115 ++++++++- include/react/Group.h | 28 ++- include/react/Signal.h | 133 +++++++++-- include/react/detail/IReactiveGraph.h | 50 ++-- include/react/detail/graph/AlgorithmNodes.h | 94 +++++--- include/react/detail/graph/EventNodes.h | 228 ++++++++++++------ include/react/detail/graph/GraphBase.h | 16 +- include/react/detail/graph/ObserverNodes.h | 35 +-- include/react/detail/graph/PropagationST.h | 251 +++++++++++++++----- include/react/detail/graph/SignalNodes.h | 209 ++++++++++++---- 13 files changed, 941 insertions(+), 312 deletions(-) diff --git a/examples/src/BasicEvents.cpp b/examples/src/BasicEvents.cpp index b9a7cfbd..0f4f3f06 100644 --- a/examples/src/BasicEvents.cpp +++ b/examples/src/BasicEvents.cpp @@ -237,12 +237,46 @@ namespace example5 /////////////////////////////////////////////////////////////////////////////////////////////////// int main() { - example1::v1::Run(); + using namespace std; + using namespace react; + + ReactiveGroup<> group; + + auto ev1 = EventSource( group ); + auto ev2 = EventSource( group ); + + auto slot1 = EventSlot( ev1, group ); + auto slot2 = EventSlot( ev1, group ); + + Observer<> obs1( + [] (EventRange in) + { + for (int e : in) + cout << e << endl; + }, slot1); + + Observer<> obs2( + [] (EventRange in) + { + for (int e : in) + cout << e << endl; + }, slot2); + + ev1 << 10 << 20 << 30; + ev2 << 11 << 22 << 33; + + slot1.Set(ev2); + slot2.Set(ev2); + + ev1 << 10 << 20 << 30; + ev2 << 11 << 22 << 33; + + /*example1::v1::Run(); example1::v2::Run(); example2::Run(); example3::Run(); example4::Run(); - example5::Run(); + example5::Run();*/ return 0; } \ No newline at end of file diff --git a/examples/src/BasicSignals.cpp b/examples/src/BasicSignals.cpp index 3007d199..44369987 100644 --- a/examples/src/BasicSignals.cpp +++ b/examples/src/BasicSignals.cpp @@ -218,11 +218,43 @@ namespace example5 /////////////////////////////////////////////////////////////////////////////////////////////////// int main() { - example1::Run(); + using namespace std; + using namespace react; + + ReactiveGroup<> group; + + auto sig1 = VarSignal( 10, group ); + auto sig2 = VarSignal( 22, group ); + + auto slot1 = SignalSlot( sig1, group ); + auto slot2 = SignalSlot( sig1, group ); + + printf("%d\n", slot1.Value()); + printf("%d\n", slot2.Value()); + + slot1.Set(sig2); + slot2.Set(sig2); + + printf("%d\n", slot1.Value()); + printf("%d\n", slot2.Value()); + + group.DoTransaction([&] + { + slot1.Set(sig2); + slot2.Set(sig2); + }); + + group.EnqueueTransaction([&] + { + slot1.Set(sig2); + slot2.Set(sig2); + }); + + /*example1::Run(); example2::Run(); example3::Run(); example4::Run(); - example5::Run(); + example5::Run();*/ return 0; } \ No newline at end of file diff --git a/include/react/API.h b/include/react/API.h index dbbf88f9..928d1007 100644 --- a/include/react/API.h +++ b/include/react/API.h @@ -59,18 +59,24 @@ template class ReactiveGroup; // Signals -template +template class SignalBase; -template +template class VarSignalBase; -template +template +class SignalSlotBase; + +template class Signal; -template +template class VarSignal; +template +class SignalSlot; + // Events enum class Token; @@ -80,13 +86,17 @@ class EventBase; template class EventSourceBase; +template +class EventSlotBase; + template class Event; template class EventSource; - +template +class EventSlot; // Observers template diff --git a/include/react/Event.h b/include/react/Event.h index 13fdcb5c..2c9222fd 100644 --- a/include/react/Event.h +++ b/include/react/Event.h @@ -100,9 +100,6 @@ class EventBase template class EventSourceBase : public EventBase { -private: - using NodeType = REACT_IMPL::EventSourceNode; - public: using EventBase::EventBase; @@ -137,7 +134,7 @@ class EventSourceBase : public EventBase using REACT_IMPL::PrivateReactiveGroupInterface; using SrcNodeType = REACT_IMPL::EventSourceNode; - return std::make_shared(PrivateReactiveGroupInterface::GraphPtr(group)); + return std::make_shared(PrivateReactiveGroupInterface::GraphPtr(group)); } private: @@ -145,9 +142,10 @@ class EventSourceBase : public EventBase void EmitValue(T&& value) { using REACT_IMPL::NodeId; - using REACT_IMPL::IReactiveGraph; + using REACT_IMPL::ReactiveGraph; + using SrcNodeType = REACT_IMPL::EventSourceNode; - NodeType* castedPtr = static_cast(this->NodePtr().get()); + SrcNodeType* castedPtr = static_cast(this->NodePtr().get()); NodeId nodeId = castedPtr->GetNodeId(); auto& graphPtr = NodePtr()->GraphPtr(); @@ -155,6 +153,55 @@ class EventSourceBase : public EventBase } }; +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// EventSlotBase +/////////////////////////////////////////////////////////////////////////////////////////////////// +template +class EventSlotBase : public EventBase +{ +public: + using EventBase::EventBase; + + void Set(const EventBase& newInput) + { SetInput(newInput); } + + void operator<<=(const EventBase& newInput) + { SetInput(newInput); } + +protected: + EventSlotBase() = default; + + EventSlotBase(const EventSlotBase&) = default; + EventSlotBase& operator=(const EventSlotBase&) = default; + + EventSlotBase(EventSlotBase&&) = default; + EventSlotBase& operator=(EventSlotBase&&) = default; + + auto CreateSlotNode(const EventBase& input, const ReactiveGroupBase& group) -> decltype(auto) + { + using REACT_IMPL::PrivateNodeInterface; + using REACT_IMPL::PrivateReactiveGroupInterface; + using SlotNodeType = REACT_IMPL::EventSlotNode; + + return std::make_shared(PrivateReactiveGroupInterface::GraphPtr(group), PrivateNodeInterface::NodePtr(input)); + } + +private: + void SetInput(const EventBase& newInput) + { + using REACT_IMPL::PrivateNodeInterface; + using REACT_IMPL::NodeId; + using REACT_IMPL::ReactiveGraph; + using SlotNodeType = REACT_IMPL::EventSlotNode; + + SlotNodeType* castedPtr = static_cast(this->NodePtr().get()); + + NodeId nodeId = castedPtr->GetInputNodeId(); + auto& graphPtr = NodePtr()->GraphPtr(); + graphPtr->AddInput(nodeId, [castedPtr, &newInput] { castedPtr->SetInput(PrivateNodeInterface::NodePtr(newInput)); }); + } +}; + /////////////////////////////////////////////////////////////////////////////////////////////////// /// Event /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -277,6 +324,62 @@ class EventSource : public EventSourceBase { EventSource::EventSourceBase::operator=(std::move(other)); return *this; } }; +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// EventSlot +/////////////////////////////////////////////////////////////////////////////////////////////////// +template +class EventSlot : public EventSlotBase +{ +public: + using EventSlotBase::EventSlotBase; + + using ValueType = E; + + EventSlot() = delete; + + EventSlot(const EventSlot&) = delete; + EventSlot& operator=(const EventSlot&) = delete; + + EventSlot(EventSlot&&) = default; + EventSlot& operator=(EventSlot&&) = default; + + // Construct with value + EventSlot(const EventBase& input, const ReactiveGroupBase& group) : + EventSlot::EventSlotBase( REACT_IMPL::NodeCtorTag{ }, CreateSlotNode(input, group) ) + { } +}; + +template +class EventSlot : public EventSlotBase +{ +public: + using EventSlotBase::EventSlotBase; + + using ValueType = E; + + EventSlot() = delete; + + EventSlot(const EventSlot&) = default; + EventSlot& operator=(const EventSlot&) = default; + + EventSlot(EventSlot&&) = default; + EventSlot& operator=(EventSlot&&) = default; + + // Construct from unique + EventSlot(EventSlot&& other) : + EventSlot::EventSlotBase( std::move(other) ) + { } + + // Assign from unique + EventSlot& operator=(EventSlot&& other) + { EventSlot::EventSlotBase::operator=(std::move(other)); return *this; } + + // Construct with value + EventSlot(const SignalBase& input, const ReactiveGroupBase& group) : + EventSlot::EventSlotBase( REACT_IMPL::NodeCtorTag{ }, CreateSlotNode(input, group) ) + { } +}; + /////////////////////////////////////////////////////////////////////////////////////////////////// /// Merge /////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/include/react/Group.h b/include/react/Group.h index c8324d1c..4ab5d2af 100644 --- a/include/react/Group.h +++ b/include/react/Group.h @@ -140,7 +140,7 @@ void AsyncTransaction(TransactionFlagsT flags, TransactionStatus& status, F&& fu /////////////////////////////////////////////////////////////////////////////////////////////////// class ReactiveGroupBase { - using GraphType = REACT_IMPL::SingleThreadedGraph; + using GraphType = REACT_IMPL::ReactiveGraph; public: ReactiveGroupBase() : @@ -157,11 +157,15 @@ class ReactiveGroupBase template void DoTransaction(F&& func) - { DoTransaction(TransactionFlags::none, std::forward(func)); } + { graphPtr_->DoTransaction(std::forward(func)); } template - void DoTransaction(TransactionFlags flags, F&& func) - { graphPtr_->DoTransaction(flags, std::forward(func)); } + void EnqueueTransaction(F&& func) + { EnqueueTransaction(TransactionFlags::none, std::forward(func)); } + + template + void EnqueueTransaction(TransactionFlags flags, F&& func) + { graphPtr_->EnqueueTransaction(flags, std::forward(func)); } protected: auto GraphPtr() -> std::shared_ptr& @@ -229,31 +233,31 @@ struct PrivateNodeInterface { return base.NodePtr(); } template - static auto GraphPtr(const TBase& base) -> const std::shared_ptr& + static auto GraphPtr(const TBase& base) -> const std::shared_ptr& { return base.NodePtr()->GraphPtr(); } template - static auto GraphPtr(TBase& base) -> std::shared_ptr& + static auto GraphPtr(TBase& base) -> std::shared_ptr& { return base.NodePtr()->GraphPtr(); } }; struct PrivateReactiveGroupInterface { - static auto GraphPtr(const ReactiveGroupBase& group) -> const std::shared_ptr& + static auto GraphPtr(const ReactiveGroupBase& group) -> const std::shared_ptr& { return group.GraphPtr(); } - static auto GraphPtr(ReactiveGroupBase& group) -> std::shared_ptr& + static auto GraphPtr(ReactiveGroupBase& group) -> std::shared_ptr& { return group.GraphPtr(); } }; template -static auto GetCheckedGraphPtr(const TBase1& dep1, const TBases& ... deps) -> const std::shared_ptr& +static auto GetCheckedGraphPtr(const TBase1& dep1, const TBases& ... deps) -> const std::shared_ptr& { - const std::shared_ptr& graphPtr1 = PrivateNodeInterface::GraphPtr(dep1); + const std::shared_ptr& graphPtr1 = PrivateNodeInterface::GraphPtr(dep1); - std::initializer_list rawGraphPtrs = { PrivateNodeInterface::GraphPtr(deps).get() ... }; + std::initializer_list rawGraphPtrs = { PrivateNodeInterface::GraphPtr(deps).get() ... }; - bool isSameGraphForAllDeps = std::all_of(rawGraphPtrs.begin(), rawGraphPtrs.end(), [&] (IReactiveGraph* p) { return p == graphPtr1.get(); }); + bool isSameGraphForAllDeps = std::all_of(rawGraphPtrs.begin(), rawGraphPtrs.end(), [&] (ReactiveGraph* p) { return p == graphPtr1.get(); }); REACT_ASSERT(isSameGraphForAllDeps, "All dependencies must belong to the same group."); diff --git a/include/react/Signal.h b/include/react/Signal.h index 22e4e548..dab00344 100644 --- a/include/react/Signal.h +++ b/include/react/Signal.h @@ -112,8 +112,7 @@ class VarSignalBase : public SignalBase VarSignalBase(VarSignalBase&&) = default; VarSignalBase& operator=(VarSignalBase&&) = default; - template - auto CreateVarNode(const TGroup& group) -> decltype(auto) + auto CreateVarNode(const ReactiveGroupBase& group) -> decltype(auto) { using REACT_IMPL::PrivateReactiveGroupInterface; using VarNodeType = REACT_IMPL::VarSignalNode; @@ -121,8 +120,8 @@ class VarSignalBase : public SignalBase return std::make_shared(PrivateReactiveGroupInterface::GraphPtr(group)); } - template - auto CreateVarNode(T&& value, const TGroup& group) -> decltype(auto) + template + auto CreateVarNode(T&& value, const ReactiveGroupBase& group) -> decltype(auto) { using REACT_IMPL::PrivateReactiveGroupInterface; using VarNodeType = REACT_IMPL::VarSignalNode; @@ -135,7 +134,7 @@ class VarSignalBase : public SignalBase void SetValue(T&& newValue) { using REACT_IMPL::NodeId; - using REACT_IMPL::IReactiveGraph; + using REACT_IMPL::ReactiveGraph; using VarNodeType = REACT_IMPL::VarSignalNode; VarNodeType* castedPtr = static_cast(this->NodePtr().get()); @@ -149,7 +148,7 @@ class VarSignalBase : public SignalBase void ModifyValue(const F& func) { using REACT_IMPL::NodeId; - using REACT_IMPL::IReactiveGraph; + using REACT_IMPL::ReactiveGraph; using VarNodeType = REACT_IMPL::VarSignalNode; VarNodeType* castedPtr = static_cast(this->NodePtr().get()); @@ -160,6 +159,55 @@ class VarSignalBase : public SignalBase } }; +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// SignalSlotBase +/////////////////////////////////////////////////////////////////////////////////////////////////// +template +class SignalSlotBase : public SignalBase +{ +public: + using SignalBase::SignalBase; + + void Set(const SignalBase& newInput) + { SetInput(newInput); } + + void operator<<=(const SignalBase& newInput) + { SetInput(newInput); } + +protected: + SignalSlotBase() = default; + + SignalSlotBase(const SignalSlotBase&) = default; + SignalSlotBase& operator=(const SignalSlotBase&) = default; + + SignalSlotBase(SignalSlotBase&&) = default; + SignalSlotBase& operator=(SignalSlotBase&&) = default; + + auto CreateSlotNode(const SignalBase& input, const ReactiveGroupBase& group) -> decltype(auto) + { + using REACT_IMPL::PrivateNodeInterface; + using REACT_IMPL::PrivateReactiveGroupInterface; + using SlotNodeType = REACT_IMPL::SignalSlotNode; + + return std::make_shared(PrivateReactiveGroupInterface::GraphPtr(group), PrivateNodeInterface::NodePtr(input)); + } + +private: + void SetInput(const SignalBase& newInput) + { + using REACT_IMPL::PrivateNodeInterface; + using REACT_IMPL::NodeId; + using REACT_IMPL::ReactiveGraph; + using SlotNodeType = REACT_IMPL::SignalSlotNode; + + SlotNodeType* castedPtr = static_cast(this->NodePtr().get()); + + NodeId nodeId = castedPtr->GetInputNodeId(); + auto& graphPtr = NodePtr()->GraphPtr(); + graphPtr->AddInput(nodeId, [castedPtr, &newInput] { castedPtr->SetInput(PrivateNodeInterface::NodePtr(newInput)); }); + } +}; + /////////////////////////////////////////////////////////////////////////////////////////////////// /// Signal /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -219,7 +267,7 @@ class Signal : public SignalBase }; /////////////////////////////////////////////////////////////////////////////////////////////////// -/// Signal +/// VarSignal /////////////////////////////////////////////////////////////////////////////////////////////////// template class VarSignal : public VarSignalBase @@ -273,7 +321,7 @@ class VarSignal : public VarSignalBase // Assign from unique VarSignal& operator=(VarSignal&& other) - { VarSignal::SignalBase::operator=(std::move(other)); return *this; } + { VarSignal::VarSignalBase::operator=(std::move(other)); return *this; } // Construct with default template @@ -289,15 +337,70 @@ class VarSignal : public VarSignalBase }; /////////////////////////////////////////////////////////////////////////////////////////////////// -/// Flatten +/// SignalSlot /////////////////////////////////////////////////////////////////////////////////////////////////// -/*template -auto Flatten(const SignalBase>& outer) -> Signal +template +class SignalSlot : public SignalSlotBase { - return Signal( - std::make_shared, TInner>>( - GetNodePtr(outer), GetNodePtr(outer.Value()))); -}*/ +public: + using SignalSlotBase::SignalSlotBase; + + using ValueType = S; + + SignalSlot() = delete; + + SignalSlot(const SignalSlot&) = delete; + SignalSlot& operator=(const SignalSlot&) = delete; + + SignalSlot(SignalSlot&&) = default; + SignalSlot& operator=(SignalSlot&&) = default; + + // Construct with default + explicit SignalSlot(const ReactiveGroupBase& group) : + SignalSlot::SignalSlotBase( REACT_IMPL::NodeCtorTag{ }, CreateSlotNode( group) ) + { } + + // Construct with value + SignalSlot(const SignalBase& input, const ReactiveGroupBase& group) : + SignalSlot::SignalSlotBase( REACT_IMPL::NodeCtorTag{ }, CreateSlotNode(input, group) ) + { } +}; + +template +class SignalSlot : public SignalSlotBase +{ +public: + using SignalSlotBase::SignalSlotBase; + + using ValueType = S; + + SignalSlot() = delete; + + SignalSlot(const SignalSlot&) = default; + SignalSlot& operator=(const SignalSlot&) = default; + + SignalSlot(SignalSlot&&) = default; + SignalSlot& operator=(SignalSlot&&) = default; + + // Construct from unique + SignalSlot(SignalSlot&& other) : + SignalSlot::SignalSlotBase( std::move(other) ) + { } + + // Assign from unique + SignalSlot& operator=(SignalSlot&& other) + { SignalSlot::SignalSlotBase::operator=(std::move(other)); return *this; } + + // Construct with default + explicit SignalSlot(const ReactiveGroupBase& group) : + SignalSlot::SignalSlotBase( REACT_IMPL::NodeCtorTag{ }, CreateSlotNode( group) ) + { } + + // Construct with value + SignalSlot(const SignalBase& input, const ReactiveGroupBase& group) : + SignalSlot::SignalSlotBase( REACT_IMPL::NodeCtorTag{ }, CreateSlotNode(input, group) ) + { } +}; /******************************************/ REACT_END /******************************************/ diff --git a/include/react/detail/IReactiveGraph.h b/include/react/detail/IReactiveGraph.h index e081844f..594f3801 100644 --- a/include/react/detail/IReactiveGraph.h +++ b/include/react/detail/IReactiveGraph.h @@ -13,6 +13,7 @@ #include #include +#include #include #include "react/API.h" @@ -26,48 +27,28 @@ /////////////////////////////////////////////////////////////////////////////////////////////////// using NodeId = size_t; using TurnId = size_t; +using LinkId = size_t; static NodeId invalid_node_id = (std::numeric_limits::max)(); static TurnId invalid_turn_id = (std::numeric_limits::max)(); +static LinkId invalid_link_id = (std::numeric_limits::max)(); enum class UpdateResult { unchanged, - changed, - shifted + changed }; -enum class NodeFlags +enum class NodeCategory { - none = 0, - input = 1 << 0, - output = 1 << 1, - dynamic = 1 << 2, - buffered = 1 << 3 + normal, + input, + dyninput, + output, + link }; -REACT_DEFINE_BITMASK_OPERATORS(NodeFlags) -struct IReactiveGraph; -struct IReactiveNode; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// IReactiveGraph -/////////////////////////////////////////////////////////////////////////////////////////////////// -struct IReactiveGraph -{ - virtual ~IReactiveGraph() = default; - - virtual NodeId RegisterNode(IReactiveNode* nodePtr, NodeFlags flags) = 0; - virtual void UnregisterNode(NodeId node) = 0; - - virtual void OnNodeAttach(NodeId nodeId, NodeId parentId) = 0; - virtual void OnNodeDetach(NodeId nodeId, NodeId parentId) = 0; - - virtual void OnDynamicNodeAttach(NodeId nodeId, NodeId parentId, TurnId turn) = 0; - virtual void OnDynamicNodeDetach(NodeId nodeId, NodeId parentId, TurnId turn) = 0; - - virtual void AddInput(NodeId nodeId, std::function inputCallback) = 0; -}; +class ReactiveGraph; /////////////////////////////////////////////////////////////////////////////////////////////////// /// IReactiveNode @@ -78,11 +59,16 @@ struct IReactiveNode virtual const char* GetNodeType() const = 0; - virtual UpdateResult Update(TurnId turnId) = 0; + virtual UpdateResult Update(TurnId turnId, int successorCount) = 0; virtual int GetDependencyCount() const = 0; +}; + +using LinkOutputList = std::vector>; - virtual void ClearBuffer() = 0; +struct ILinkOutputNode : public IReactiveNode +{ + virtual void CollectOutput(LinkOutputList& output) = 0; }; /****************************************/ REACT_IMPL_END /***************************************/ diff --git a/include/react/detail/graph/AlgorithmNodes.h b/include/react/detail/graph/AlgorithmNodes.h index b5bb7aa6..62ff5c9a 100644 --- a/include/react/detail/graph/AlgorithmNodes.h +++ b/include/react/detail/graph/AlgorithmNodes.h @@ -86,7 +86,7 @@ class IterateNode : public SignalNode { public: template - IterateNode(const std::shared_ptr& graphPtr, T&& init, FIn&& func, const std::shared_ptr>& events) : + IterateNode(const std::shared_ptr& graphPtr, T&& init, FIn&& func, const std::shared_ptr>& events) : IterateNode::SignalNode( graphPtr, std::forward(init) ), func_( std::forward(func) ), events_( events ) @@ -101,10 +101,12 @@ class IterateNode : public SignalNode this->UnregisterMe(); } - virtual UpdateResult Update(TurnId turnId) override + virtual UpdateResult Update(TurnId turnId, int successorCount) override { S newValue = func_(EventRange( events_->Events() ), this->Value()); + events_->DecrementPendingSuccessorCount(); + if (! (newValue == this->Value())) { this->Value() = std::move(newValue); @@ -136,7 +138,7 @@ class IterateByRefNode : public SignalNode { public: template - IterateByRefNode(const std::shared_ptr& graphPtr, T&& init, FIn&& func, const std::shared_ptr>& events) : + IterateByRefNode(const std::shared_ptr& graphPtr, T&& init, FIn&& func, const std::shared_ptr>& events) : IterateByRefNode::SignalNode( graphPtr, std::forward(init) ), func_( std::forward(func) ), events_( events ) @@ -151,10 +153,12 @@ class IterateByRefNode : public SignalNode this->UnregisterMe(); } - virtual UpdateResult Update(TurnId turnId) override + virtual UpdateResult Update(TurnId turnId, int successorCount) override { func_(EventRange( events_->Events() ), this->Value()); + events_->DecrementPendingSuccessorCount(); + // Always assume change return UpdateResult::changed; } @@ -179,7 +183,7 @@ class SyncedIterateNode : public SignalNode { public: template - SyncedIterateNode(const std::shared_ptr& graphPtr, T&& init, FIn&& func, const std::shared_ptr>& events, const std::shared_ptr>& ... syncs) : + SyncedIterateNode(const std::shared_ptr& graphPtr, T&& init, FIn&& func, const std::shared_ptr>& events, const std::shared_ptr>& ... syncs) : SyncedIterateNode::SignalNode( graphPtr, std::forward(init) ), func_( std::forward(func) ), events_( events ), @@ -197,8 +201,12 @@ class SyncedIterateNode : public SignalNode this->UnregisterMe(); } - virtual UpdateResult Update(TurnId turnId) override + virtual UpdateResult Update(TurnId turnId, int successorCount) override { + // Updates might be triggered even if only sync nodes changed. Ignore those. + if (events_->Events().empty()) + return UpdateResult::unchanged; + S newValue = apply( [this] (const auto& ... syncs) { @@ -206,6 +214,8 @@ class SyncedIterateNode : public SignalNode }, syncHolder_); + events_->DecrementPendingSuccessorCount(); + if (! (newValue == this->Value())) { this->Value() = std::move(newValue); @@ -239,7 +249,7 @@ class SyncedIterateByRefNode : public SignalNode { public: template - SyncedIterateByRefNode(const std::shared_ptr& graphPtr, T&& init, FIn&& func, const std::shared_ptr>& events, const std::shared_ptr>& ... syncs) : + SyncedIterateByRefNode(const std::shared_ptr& graphPtr, T&& init, FIn&& func, const std::shared_ptr>& events, const std::shared_ptr>& ... syncs) : SyncedIterateByRefNode::SignalNode( graphPtr, std::forward(init) ), func_( std::forward(func) ), events_( events ), @@ -257,27 +267,23 @@ class SyncedIterateByRefNode : public SignalNode this->UnregisterMe(); } - virtual UpdateResult Update(TurnId turnId) override + virtual UpdateResult Update(TurnId turnId, int successorCount) override { - events_->SetCurrentTurn(turnId); + // Updates might be triggered even if only sync nodes changed. Ignore those. + if (events_->Events().empty()) + return UpdateResult::unchanged; - bool changed = false; + apply( + [this] (const auto& ... args) + { + func_(EventRange( events_->Events() ), this->Value(), args->Value() ...); + }, + syncHolder_); - if (! events_->Events().empty()) - { - apply( - [this] (const auto& ... args) - { - func_(EventRange( events_->Events() ), this->Value(), args->Value() ...); - }, - syncHolder_); + events_->DecrementPendingSuccessorCount(); + this->SetPendingSuccessorCount(successorCount); - return UpdateResult::changed; - } - else - { - return UpdateResult::unchanged; - } + return UpdateResult::changed; } virtual const char* GetNodeType() const override @@ -302,7 +308,7 @@ class HoldNode : public SignalNode { public: template - HoldNode(const std::shared_ptr& graphPtr, T&& init, const std::shared_ptr>& events) : + HoldNode(const std::shared_ptr& graphPtr, T&& init, const std::shared_ptr>& events) : HoldNode::SignalNode( graphPtr, std::forward(init) ), events_( events ) { @@ -319,7 +325,7 @@ class HoldNode : public SignalNode virtual const char* GetNodeType() const override { return "HoldNode"; } - virtual UpdateResult Update(TurnId turnId) override + virtual UpdateResult Update(TurnId turnId, int successorCount) override { bool changed = false; @@ -332,6 +338,8 @@ class HoldNode : public SignalNode changed = true; this->Value() = newValue; } + + events_->DecrementPendingSuccessorCount(); } if (changed) @@ -354,7 +362,7 @@ template class SnapshotNode : public SignalNode { public: - SnapshotNode(const std::shared_ptr& graphPtr, const std::shared_ptr>& target, const std::shared_ptr>& trigger) : + SnapshotNode(const std::shared_ptr& graphPtr, const std::shared_ptr>& target, const std::shared_ptr>& trigger) : SnapshotNode::SignalNode( graphPtr, target->Value() ), target_( target ), trigger_( trigger ) @@ -371,21 +379,21 @@ class SnapshotNode : public SignalNode this->UnregisterMe(); } - virtual UpdateResult Update(TurnId turnId) override + virtual UpdateResult Update(TurnId turnId, int successorCount) override { - trigger_->SetCurrentTurn(turnId); - bool changed = false; if (! trigger_->Events().empty()) { const S& newValue = target_->Value(); - if (! Equals(newValue, this->Value())) + if (! (newValue == this->Value())) { changed = true; this->Value() = newValue; } + + trigger_->DecrementPendingSuccessorCount(); } if (changed) @@ -412,11 +420,11 @@ template class MonitorNode : public EventStreamNode { public: - MonitorNode(const std::shared_ptr& graphPtr, const std::shared_ptr>& target) : + MonitorNode(const std::shared_ptr& graphPtr, const std::shared_ptr>& target) : MonitorNode::EventStreamNode( graphPtr ), target_( target ) { - this->RegisterMe(NodeFlags::buffered); + this->RegisterMe(); this->AttachToMe(target->GetNodeId()); } @@ -426,9 +434,12 @@ class MonitorNode : public EventStreamNode this->UnregisterMe(); } - virtual UpdateResult Update(TurnId turnId) override + virtual UpdateResult Update(TurnId turnId, int successorCount) override { this->Events().push_back(target_->Value()); + + this->SetPendingSuccessorCount(successorCount); + return UpdateResult::changed; } @@ -449,12 +460,12 @@ template class PulseNode : public EventStreamNode { public: - PulseNode(const std::shared_ptr& graphPtr, const std::shared_ptr>& target, const std::shared_ptr>& trigger) : + PulseNode(const std::shared_ptr& graphPtr, const std::shared_ptr>& target, const std::shared_ptr>& trigger) : PulseNode::EventStreamNode( graphPtr ), target_( target ), trigger_( trigger ) { - this->RegisterMe(NodeFlags::buffered); + this->RegisterMe(); this->AttachToMe(target->GetNodeId()); this->AttachToMe(trigger->GetNodeId()); } @@ -466,19 +477,26 @@ class PulseNode : public EventStreamNode this->UnregisterMe(); } - virtual UpdateResult Update(TurnId turnId) override + virtual UpdateResult Update(TurnId turnId, int successorCount) override { for (size_t i=0; iEvents().size(); i++) this->Events().push_back(target_->Value()); + trigger_->DecrementPendingSuccessorCount(); + if (! this->Events().empty()) + { + this->SetPendingSuccessorCount(successorCount); return UpdateResult::changed; + } else + { return UpdateResult::unchanged; + } } virtual const char* GetNodeType() const override - { return "PulseNode"; } + { return "Pulse"; } virtual int GetDependencyCount() const override { return 2; } diff --git a/include/react/detail/graph/EventNodes.h b/include/react/detail/graph/EventNodes.h index caf2e049..6a457a98 100644 --- a/include/react/detail/graph/EventNodes.h +++ b/include/react/detail/graph/EventNodes.h @@ -27,19 +27,19 @@ /////////////////////////////////////////////////////////////////////////////////////////////////// /// Iterators for event processing /////////////////////////////////////////////////////////////////////////////////////////////////// -template +template class EventRange { public: - using const_iterator = typename std::vector::const_iterator; - using size_type = typename std::vector::size_type; + using const_iterator = typename std::vector::const_iterator; + using size_type = typename std::vector::size_type; EventRange() = delete; EventRange(const EventRange&) = default; EventRange& operator=(const EventRange&) = default; - explicit EventRange(const std::vector& data) : + explicit EventRange(const std::vector& data) : data_( data ) { } @@ -56,11 +56,11 @@ class EventRange { return data_.empty(); } private: - const std::vector& data_; + const std::vector& data_; }; -template -using EventSink = std::back_insert_iterator>; +template +using EventSink = std::back_insert_iterator>; /******************************************/ REACT_END /******************************************/ @@ -69,17 +69,17 @@ using EventSink = std::back_insert_iterator>; /////////////////////////////////////////////////////////////////////////////////////////////////// /// Forward declarations /////////////////////////////////////////////////////////////////////////////////////////////////// -template +template class SignalNode; /////////////////////////////////////////////////////////////////////////////////////////////////// /// EventStreamNode /////////////////////////////////////////////////////////////////////////////////////////////////// -template +template class EventStreamNode : public NodeBase { public: - using StorageType = std::vector; + using StorageType = std::vector; EventStreamNode(EventStreamNode&&) = default; EventStreamNode& operator=(EventStreamNode&&) = default; @@ -87,7 +87,7 @@ class EventStreamNode : public NodeBase EventStreamNode(const EventStreamNode&) = delete; EventStreamNode& operator=(const EventStreamNode&) = delete; - explicit EventStreamNode(const std::shared_ptr& graphPtr) : + explicit EventStreamNode(const std::shared_ptr& graphPtr) : NodeBase( graphPtr ) { } @@ -97,11 +97,37 @@ class EventStreamNode : public NodeBase const StorageType& Events() const { return events_; } - virtual void ClearBuffer() override - { events_.clear(); }; + + void SetPendingSuccessorCount(int count) + { + if (count == 0) + { + // If there are no successors, buffer is cleared immediately. + events_.clear(); + } + else + { + // Otherwise, the last finished successor clears it. + pendingSuccessorCount_ = count; + } + } + + void DecrementPendingSuccessorCount() + { + // Not all predecessors of a node might be visited during a turn. + // In this case, the count is zero and the call to this function should be ignored. + if (pendingSuccessorCount_ == 0) + return; + + // Last successor to arrive clears the buffer. + if (pendingSuccessorCount_-- == 1) + events_.clear(); + }; private: StorageType events_; + + std::atomic pendingSuccessorCount_ = 0; }; /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -111,9 +137,9 @@ template class EventSourceNode : public EventStreamNode { public: - EventSourceNode(const std::shared_ptr& graphPtr) : + EventSourceNode(const std::shared_ptr& graphPtr) : EventSourceNode::EventStreamNode( graphPtr ) - { this->RegisterMe(NodeFlags::buffered | NodeFlags::input); } + { this->RegisterMe(NodeCategory::input); } ~EventSourceNode() { this->UnregisterMe(); } @@ -124,10 +150,11 @@ class EventSourceNode : public EventStreamNode virtual int GetDependencyCount() const override { return 0; } - virtual UpdateResult Update(TurnId turnId) override + virtual UpdateResult Update(TurnId turnId, int successorCount) override { - if (this->Events().size() > 0) - { + if (! this->Events().empty()) + { + this->SetPendingSuccessorCount(successorCount); return UpdateResult::changed; } else @@ -138,9 +165,7 @@ class EventSourceNode : public EventStreamNode template void EmitValue(U&& value) - { - this->Events().push_back(std::forward(value)); - } + { this->Events().push_back(std::forward(value)); } }; /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -150,11 +175,11 @@ template class EventMergeNode : public EventStreamNode { public: - EventMergeNode(const std::shared_ptr& graphPtr, const std::shared_ptr>& ... deps) : + EventMergeNode(const std::shared_ptr& graphPtr, const std::shared_ptr>& ... deps) : EventMergeNode::EventStreamNode( graphPtr ), depHolder_( deps ... ) { - this->RegisterMe(NodeFlags::buffered); + this->RegisterMe(); REACT_EXPAND_PACK(this->AttachToMe(deps->GetNodeId())); } @@ -164,14 +189,19 @@ class EventMergeNode : public EventStreamNode this->UnregisterMe(); } - virtual UpdateResult Update(TurnId turnId) override + virtual UpdateResult Update(TurnId turnId, int successorCount) override { apply([this] (const auto& ... deps) { REACT_EXPAND_PACK(MergeFromDep(deps)); }, depHolder_); if (! this->Events().empty()) + { + this->SetPendingSuccessorCount(successorCount); return UpdateResult::changed; + } else + { return UpdateResult::unchanged; + } } virtual const char* GetNodeType() const override @@ -185,70 +215,108 @@ class EventMergeNode : public EventStreamNode void MergeFromDep(const std::shared_ptr>& other) { this->Events().insert(this->Events().end(), other->Events().begin(), other->Events().end()); + other->DecrementPendingSuccessorCount(); } std::tuple> ...> depHolder_; }; /////////////////////////////////////////////////////////////////////////////////////////////////// -/// EventFlattenNode +/// EventSlotNode /////////////////////////////////////////////////////////////////////////////////////////////////// -template -class EventFlattenNode : public EventStreamNode +template +class EventSlotNode : public EventStreamNode { public: - EventFlattenNode(const std::shared_ptr& graphPtr, const std::shared_ptr>& outer, const std::shared_ptr>& inner) : - EventFlattenNode::EventStreamNode( graphPtr ), - outer_( outer ), - inner_( inner ) + EventSlotNode(const std::shared_ptr& graphPtr, const std::shared_ptr>& dep) : + EventSlotNode::EventStreamNode( graphPtr ), + slotInput_( *this, dep ) { - this->RegisterMe(NodeFlags::buffered | NodeFlags::dynamic); - this->AttachToMe(outer->GetNodeId()); - this->AttachToMe(inner->GetNodeId()); + slotInput_.nodeId = GraphPtr()->RegisterNode(&slotInput_, NodeCategory::dyninput); + this->RegisterMe(); + + this->AttachToMe(slotInput_.nodeId); + this->AttachToMe(dep->GetNodeId()); } - ~EventFlattenNode() + ~EventSlotNode() { - this->DetachFromMe(inner->GetNodeId()); - this->DetachFromMe(outer->GetNodeId()); + this->DetachFromMe(slotInput_.dep->GetNodeId()); + this->DetachFromMe(slotInput_.nodeId); + this->UnregisterMe(); + GraphPtr()->UnregisterNode(slotInput_.nodeId); } virtual const char* GetNodeType() const override - { return "EventFlatten"; } + { return "EventSlot"; } virtual int GetDependencyCount() const override { return 2; } - virtual UpdateResult Update(TurnId turnId) override + virtual UpdateResult Update(TurnId turnId, int successorCount) override { - auto newInner = GetNodePtr(outer_->Value()); + this->Events().insert(this->Events().end(), slotInput_.dep->Events().begin(), slotInput_.dep->Events().end()); - if (newInner != inner_) + slotInput_.dep->DecrementPendingSuccessorCount(); + + if (! this->Events().empty()) + { + this->SetPendingSuccessorCount(successorCount); + return UpdateResult::changed; + } + else { - newInner->SetCurrentTurn(turnId); + return UpdateResult::unchanged; + } + } + + void SetInput(const std::shared_ptr>& newInput) + { slotInput_.newDep = newInput; } + + NodeId GetInputNodeId() const + { return slotInput_.nodeId; } - // Topology has been changed - auto oldInner = inner_; - inner_ = newInner; +private: + struct VirtualInputNode : public IReactiveNode + { + VirtualInputNode(EventSlotNode& parentIn, const std::shared_ptr>& depIn) : + parent( parentIn ), + dep( depIn ) + { } - this->DynamicDetachFromMe(oldInner->GetNodeId(), 0); - this->DynamicAttachToMe(newInner->GetNodeId(), 0); + virtual const char* GetNodeType() const override + { return "EventSlotVirtualInput"; } + + virtual int GetDependencyCount() const override + { return 0; } + + virtual UpdateResult Update(TurnId turnId, int successorCount) override + { + if (dep != newDep) + { + parent.DynamicDetachFromMe(dep->GetNodeId(), 0); + parent.DynamicAttachToMe(newDep->GetNodeId(), 0); - return UpdateResult::shifted; + dep = std::move(newDep); + return UpdateResult::changed; + } + else + { + newDep.reset(); + return UpdateResult::unchanged; + } } - this->Events().insert(this->Events().end(), inner_->Events().begin(), inner_->Events().end()); + EventSlotNode& parent; - if (! this->Events().empty()) - return UpdateResult::changed; - else - return UpdateResult::unchanged; - } + NodeId nodeId; -private: - std::shared_ptr> outer_; - std::shared_ptr> inner_; + std::shared_ptr> dep; + std::shared_ptr> newDep; + }; + + VirtualInputNode slotInput_; }; /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -259,12 +327,12 @@ class EventProcessingNode : public EventStreamNode { public: template - EventProcessingNode(const std::shared_ptr& graphPtr, FIn&& func, const std::shared_ptr>& dep) : + EventProcessingNode(const std::shared_ptr& graphPtr, FIn&& func, const std::shared_ptr>& dep) : EventProcessingNode::EventStreamNode( graphPtr ), func_( std::forward(func) ), dep_( dep ) { - this->RegisterMe(NodeFlags::buffered); + this->RegisterMe(); this->AttachToMe(dep->GetNodeId()); } @@ -274,14 +342,21 @@ class EventProcessingNode : public EventStreamNode this->UnregisterMe(); } - virtual UpdateResult Update(TurnId turnId) override + virtual UpdateResult Update(TurnId turnId, int successorCount) override { func_(EventRange( dep_->Events() ), std::back_inserter(this->Events())); + dep_->DecrementPendingSuccessorCount(); + if (! this->Events().empty()) + { + this->SetPendingSuccessorCount(successorCount); return UpdateResult::changed; + } else + { return UpdateResult::unchanged; + } } virtual const char* GetNodeType() const override @@ -304,13 +379,13 @@ class SyncedEventProcessingNode : public EventStreamNode { public: template - SyncedEventProcessingNode(const std::shared_ptr& graphPtr, FIn&& func, const std::shared_ptr>& dep, const std::shared_ptr>& ... syncs) : + SyncedEventProcessingNode(const std::shared_ptr& graphPtr, FIn&& func, const std::shared_ptr>& dep, const std::shared_ptr>& ... syncs) : SyncedEventProcessingNode::EventStreamNode( graphPtr ), func_( std::forward(func) ), dep_( dep ), syncHolder_( syncs ... ) { - this->RegisterMe(NodeFlags::buffered); + this->RegisterMe(); this->AttachToMe(dep->GetNodeId()); REACT_EXPAND_PACK(this->AttachToMe(syncs->GetNodeId())); } @@ -322,7 +397,7 @@ class SyncedEventProcessingNode : public EventStreamNode this->UnregisterMe(); } - virtual UpdateResult Update(TurnId turnId) override + virtual UpdateResult Update(TurnId turnId, int successorCount) override { // Updates might be triggered even if only sync nodes changed. Ignore those. if (dep_->Events().empty()) @@ -335,14 +410,21 @@ class SyncedEventProcessingNode : public EventStreamNode }, syncHolder_); + dep_->DecrementPendingSuccessorCount(); + if (! this->Events().empty()) + { + this->SetPendingSuccessorCount(successorCount); return UpdateResult::changed; + } else + { return UpdateResult::unchanged; + } } virtual const char* GetNodeType() const override - { return "SycnedEventProcessing"; } + { return "SyncedEventProcessing"; } virtual int GetDependencyCount() const override { return 1 + sizeof...(TSyncs); } @@ -350,7 +432,7 @@ class SyncedEventProcessingNode : public EventStreamNode private: F func_; - std::shared_ptr> dep_; + std::shared_ptr> dep_; std::tuple>...> syncHolder_; }; @@ -362,11 +444,11 @@ template class EventJoinNode : public EventStreamNode> { public: - EventJoinNode(const std::shared_ptr& graphPtr, const std::shared_ptr>& ... deps) : + EventJoinNode(const std::shared_ptr& graphPtr, const std::shared_ptr>& ... deps) : EventJoinNode::EventStreamNode( graphPtr ), slots_( deps ... ) { - this->RegisterMe(NodeFlags::buffered); + this->RegisterMe(); REACT_EXPAND_PACK(this->AttachToMe(deps->GetNodeId())); } @@ -376,9 +458,9 @@ class EventJoinNode : public EventStreamNode> this->UnregisterMe(); } - virtual UpdateResult Update(TurnId turnId) override + virtual UpdateResult Update(TurnId turnId, int successorCount) override { - // Move events into buffers + // Move events into buffers. apply([this, turnId] (Slot& ... slots) { REACT_EXPAND_PACK(FetchBuffer(turnId, slots)); }, slots_); while (true) @@ -396,7 +478,7 @@ class EventJoinNode : public EventStreamNode> if (!isReady) break; - // Pop values from buffers and emit tuple + // Pop values from buffers and emit tuple. apply( [this] (Slot& ... slots) { @@ -407,9 +489,14 @@ class EventJoinNode : public EventStreamNode> } if (! this->Events().empty()) + { + this->SetPendingSuccessorCount(successorCount); return UpdateResult::changed; + } else + { return UpdateResult::unchanged; + } } virtual const char* GetNodeType() const override @@ -434,6 +521,7 @@ class EventJoinNode : public EventStreamNode> static void FetchBuffer(TurnId turnId, Slot& slot) { slot.buffer.insert(slot.buffer.end(), slot.source->Events().begin(), slot.source->Events().end()); + slot.source->DecrementPendingSuccessorCount(); } template diff --git a/include/react/detail/graph/GraphBase.h b/include/react/detail/graph/GraphBase.h index 8466d77b..d39809bb 100644 --- a/include/react/detail/graph/GraphBase.h +++ b/include/react/detail/graph/GraphBase.h @@ -21,7 +21,7 @@ /***************************************/ REACT_IMPL_BEGIN /**************************************/ -struct IReactiveGraph; +class ReactiveGraph; /////////////////////////////////////////////////////////////////////////////////////////////////// /// NodeBase @@ -29,7 +29,7 @@ struct IReactiveGraph; class NodeBase : public IReactiveNode { public: - NodeBase(const std::shared_ptr& graphPtr) : + NodeBase(const std::shared_ptr& graphPtr) : graphPtr_( graphPtr ) { } @@ -58,15 +58,15 @@ class NodeBase : public IReactiveNode NodeId GetNodeId() const { return nodeId_; } - auto GraphPtr() const -> const std::shared_ptr& + auto GraphPtr() const -> const std::shared_ptr& { return graphPtr_; } - auto GraphPtr() -> std::shared_ptr& + auto GraphPtr() -> std::shared_ptr& { return graphPtr_; } protected: - void RegisterMe(NodeFlags flags = NodeFlags::none) - { nodeId_ = graphPtr_->RegisterNode(this, flags); } + void RegisterMe(NodeCategory category = NodeCategory::normal) + { nodeId_ = graphPtr_->RegisterNode(this, category); } void UnregisterMe() { graphPtr_->UnregisterNode(nodeId_); } @@ -84,9 +84,9 @@ class NodeBase : public IReactiveNode { graphPtr_->OnDynamicNodeDetach(nodeId_, otherNodeId, turnId); } private: - NodeId nodeId_; + NodeId nodeId_; - std::shared_ptr graphPtr_; + std::shared_ptr graphPtr_; }; /****************************************/ REACT_IMPL_END /***************************************/ diff --git a/include/react/detail/graph/ObserverNodes.h b/include/react/detail/graph/ObserverNodes.h index abdf1c6e..f8887d8b 100644 --- a/include/react/detail/graph/ObserverNodes.h +++ b/include/react/detail/graph/ObserverNodes.h @@ -35,12 +35,9 @@ class EventStreamNode; class ObserverNode : public NodeBase { public: - ObserverNode(const std::shared_ptr& graphPtr) : + ObserverNode(const std::shared_ptr& graphPtr) : ObserverNode::NodeBase( graphPtr ) { } - - virtual void ClearBuffer() override - { }; }; /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -51,12 +48,12 @@ class SignalObserverNode : public ObserverNode { public: template - SignalObserverNode(const std::shared_ptr& graphPtr, FIn&& func, const std::shared_ptr>& ... deps) : + SignalObserverNode(const std::shared_ptr& graphPtr, FIn&& func, const std::shared_ptr>& ... deps) : SignalObserverNode::ObserverNode( graphPtr ), func_( std::forward(func) ), depHolder_( deps ... ) { - this->RegisterMe(NodeFlags::output); + this->RegisterMe(NodeCategory::output); REACT_EXPAND_PACK(this->AttachToMe(deps->GetNodeId())); } @@ -72,7 +69,7 @@ class SignalObserverNode : public ObserverNode virtual int GetDependencyCount() const override { return sizeof...(TDeps); } - virtual UpdateResult Update(TurnId turnId) override + virtual UpdateResult Update(TurnId turnId, int successorCount) override { apply([this] (const auto& ... deps) { this->func_(deps->Value() ...); }, depHolder_); return UpdateResult::unchanged; @@ -92,12 +89,12 @@ class EventObserverNode : public ObserverNode { public: template - EventObserverNode(const std::shared_ptr& graphPtr, FIn&& func, const std::shared_ptr>& subject) : + EventObserverNode(const std::shared_ptr& graphPtr, FIn&& func, const std::shared_ptr>& subject) : EventObserverNode::ObserverNode( graphPtr ), func_( std::forward(func) ), subject_( subject ) { - this->RegisterMe(NodeFlags::output); + this->RegisterMe(NodeCategory::output); this->AttachToMe(subject->GetNodeId()); } @@ -113,9 +110,10 @@ class EventObserverNode : public ObserverNode virtual int GetDependencyCount() const override { return 1; } - virtual UpdateResult Update(TurnId turnId) override + virtual UpdateResult Update(TurnId turnId, int successorCount) override { func_(EventRange( subject_->Events() )); + subject_->DecrementPendingSuccessorCount(); return UpdateResult::unchanged; } @@ -133,13 +131,13 @@ class SyncedEventObserverNode : public ObserverNode { public: template - SyncedEventObserverNode(const std::shared_ptr& graphPtr, FIn&& func, const std::shared_ptr>& subject, const std::shared_ptr>& ... syncs) : + SyncedEventObserverNode(const std::shared_ptr& graphPtr, FIn&& func, const std::shared_ptr>& subject, const std::shared_ptr>& ... syncs) : SyncedEventObserverNode::ObserverNode( graphPtr ), func_( std::forward(func) ), subject_( subject ), syncHolder_( syncs ... ) { - this->RegisterMe(NodeFlags::output); + this->RegisterMe(NodeCategory::output); this->AttachToMe(subject->GetNodeId()); REACT_EXPAND_PACK(this->AttachToMe(syncs->GetNodeId())); } @@ -157,13 +155,16 @@ class SyncedEventObserverNode : public ObserverNode virtual int GetDependencyCount() const override { return 1 + sizeof...(TSyncs); } - virtual UpdateResult Update(TurnId turnId) override - { - // Update of this node could be triggered from deps, - // so make sure source doesnt contain events from last turn - subject_->SetCurrentTurn(turnId); + virtual UpdateResult Update(TurnId turnId, int successorCount) override + { + // Updates might be triggered even if only sync nodes changed. Ignore those. + if (events_->Events().empty()) + return UpdateResult::unchanged; apply([this] (const auto& ... syncs) { func_(EventRange( this->subject_->Events() ), syncs->Value() ...); }, syncHolder_); + + subject_->DecrementPendingSuccessorCount(); + return UpdateResult::unchanged; } diff --git a/include/react/detail/graph/PropagationST.h b/include/react/detail/graph/PropagationST.h index 96d4fee4..e0eb2f59 100644 --- a/include/react/detail/graph/PropagationST.h +++ b/include/react/detail/graph/PropagationST.h @@ -12,34 +12,100 @@ #include "react/detail/Defs.h" #include +#include #include #include #include +#include +#include + #include "react/common/Containers.h" #include "react/common/Types.h" #include "react/detail/IReactiveGraph.h" /***************************************/ REACT_IMPL_BEGIN /**************************************/ -class SingleThreadedGraph : public IReactiveGraph +class ReactiveGraph; + +class TransactionQueue +{ +public: + TransactionQueue(ReactiveGraph& graph) : + graph_( graph ) + { } + + TransactionQueue(const TransactionQueue&) = delete; + TransactionQueue& operator=(const TransactionQueue&) = delete; + + TransactionQueue(TransactionQueue&&) = default; + TransactionQueue& operator =(TransactionQueue&&) = default; + + template + void Push(TransactionFlags flags, F&& transaction) + { + if (count_.fetch_add(1, std::memory_order_relaxed) == 0) + tbb::task::enqueue(*new(tbb::task::allocate_root()) WorkerTask(*this)); + } + +private: + struct StoredTransaction + { + TransactionFlags flags; + std::function callback; + }; + + class WorkerTask : public tbb::task + { + public: + WorkerTask(TransactionQueue& parent) : + parent_( parent ) + { } + + tbb::task* execute() + { + parent_.ProcessQueue(); + return nullptr; + } + + private: + TransactionQueue& parent_; + }; + + void ProcessQueue(); + + size_t ProcessNextBatch(); + + tbb::concurrent_queue transactions_; + + std::atomic count_{ 0 }; + + ReactiveGraph& graph_; +}; + +class ReactiveGraph { public: - // IReactiveGraph - virtual NodeId RegisterNode(IReactiveNode* nodePtr, NodeFlags flags) override; - virtual void UnregisterNode(NodeId node) override; + NodeId RegisterNode(IReactiveNode* nodePtr, NodeCategory category); + void UnregisterNode(NodeId nodeId); - virtual void OnNodeAttach(NodeId node, NodeId parentId) override; - virtual void OnNodeDetach(NodeId node, NodeId parentId) override; + void OnNodeAttach(NodeId node, NodeId parentId); + void OnNodeDetach(NodeId node, NodeId parentId); - virtual void OnDynamicNodeAttach(NodeId node, NodeId parentId, TurnId turnId) override; - virtual void OnDynamicNodeDetach(NodeId node, NodeId parentId, TurnId turnId) override; + void OnDynamicNodeAttach(NodeId node, NodeId parentId, TurnId turnId); + void OnDynamicNodeDetach(NodeId node, NodeId parentId, TurnId turnId); - virtual void AddInput(NodeId nodeId, std::function inputCallback) override; - // ~IReactiveGraph + LinkId AddGroupLink(ILinkNodeOutput* nodePtr, NodeCategory category); + void RemoveGroupLink(LinkId nodeId); template - void DoTransaction(TransactionFlags flags, F&& transactionCallback); + void AddInput(NodeId nodeId, F&& inputCallback); + + template + void DoTransaction(F&& transactionCallback); + + template + void EnqueueTransaction(TransactionFlags flags, F&& transactionCallback); private: struct NodeData @@ -49,12 +115,12 @@ class SingleThreadedGraph : public IReactiveGraph NodeData(const NodeData&) = default; NodeData& operator=(const NodeData&) = default; - NodeData(IReactiveNode* nodePtrIn, NodeFlags flagsIn) : + NodeData(IReactiveNode* nodePtrIn, NodeCategory categoryIn) : nodePtr( nodePtrIn ), - flags( flagsIn ) + category(categoryIn) { } - NodeFlags flags = NodeFlags::none; + NodeCategory category = NodeCategory::normal; int level = 0; int newLevel = 0 ; @@ -90,35 +156,34 @@ class SingleThreadedGraph : public IReactiveGraph }; void Propagate(); + void UpdateLinkNodes(); void ScheduleSuccessors(NodeData & node); void InvalidateSuccessors(NodeData & node); - void ClearBufferedNodes(); private: - int refCount_ = 1; + TransactionQueue transactionQueue_{ *this }; TopoQueue scheduledNodes_; IndexMap nodeData_; std::vector changedInputs_; - - std::vector pendingBufferedNodes_; + std::vector scheduledLinkNodes_; bool isTransactionActive_ = false; }; -NodeId SingleThreadedGraph::RegisterNode(IReactiveNode* nodePtr, NodeFlags flags) +NodeId ReactiveGraph::RegisterNode(IReactiveNode* nodePtr, NodeCategory category) { - return nodeData_.Insert(NodeData{ nodePtr, flags }); + return nodeData_.Insert(NodeData{ nodePtr, category }); } -void SingleThreadedGraph::UnregisterNode(NodeId nodeId) +void ReactiveGraph::UnregisterNode(NodeId nodeId) { nodeData_.Remove(nodeId); } -void SingleThreadedGraph::OnNodeAttach(NodeId nodeId, NodeId parentId) +void ReactiveGraph::OnNodeAttach(NodeId nodeId, NodeId parentId) { auto& node = nodeData_[nodeId]; auto& parent = nodeData_[parentId]; @@ -129,7 +194,7 @@ void SingleThreadedGraph::OnNodeAttach(NodeId nodeId, NodeId parentId) node.level = parent.level + 1; } -void SingleThreadedGraph::OnNodeDetach(NodeId nodeId, NodeId parentId) +void ReactiveGraph::OnNodeDetach(NodeId nodeId, NodeId parentId) { auto& parent = nodeData_[parentId]; auto& successors = parent.successors; @@ -137,17 +202,18 @@ void SingleThreadedGraph::OnNodeDetach(NodeId nodeId, NodeId parentId) successors.erase(std::find(successors.begin(), successors.end(), nodeId)); } -void SingleThreadedGraph::OnDynamicNodeAttach(NodeId nodeId, NodeId parentId, TurnId turnId) +void ReactiveGraph::OnDynamicNodeAttach(NodeId nodeId, NodeId parentId, TurnId turnId) { OnNodeAttach(nodeId, parentId); } -void SingleThreadedGraph::OnDynamicNodeDetach(NodeId nodeId, NodeId parentId, TurnId turnId) +void ReactiveGraph::OnDynamicNodeDetach(NodeId nodeId, NodeId parentId, TurnId turnId) { OnNodeDetach(nodeId, parentId); } -void SingleThreadedGraph::AddInput(NodeId nodeId, std::function inputCallback) +template +void ReactiveGraph::AddInput(NodeId nodeId, F&& inputCallback) { auto& node = nodeData_[nodeId]; auto* nodePtr = node.nodePtr; @@ -163,25 +229,22 @@ void SingleThreadedGraph::AddInput(NodeId nodeId, std::function inputCal } else { + int successorCount = node.successors.size(); + // Update the node. This applies the input buffer to the node value and checks if it changed. - if (nodePtr->Update(0) == UpdateResult::changed) + if (nodePtr->Update(0, successorCount) == UpdateResult::changed) { - if (IsBitmaskSet(node.flags, NodeFlags::buffered)) - pendingBufferedNodes_.push_back(nodePtr); - // Propagate changes through the graph ScheduleSuccessors(node); if (! scheduledNodes_.IsEmpty()) Propagate(); } - - ClearBufferedNodes(); } } template -void SingleThreadedGraph::DoTransaction(TransactionFlags flags, F&& transactionCallback) +void ReactiveGraph::DoTransaction(F&& transactionCallback) { // Transaction callback may add multiple inputs. isTransactionActive_ = true; @@ -194,10 +257,12 @@ void SingleThreadedGraph::DoTransaction(TransactionFlags flags, F&& transactionC auto& node = nodeData_[nodeId]; auto* nodePtr = node.nodePtr; - if (nodePtr->Update(0) == UpdateResult::changed) + int successorCount = node.successors.size(); + + if (nodePtr->Update(0, successorCount) == UpdateResult::changed) { - if (IsBitmaskSet(node.flags, NodeFlags::buffered)) - pendingBufferedNodes_.push_back(nodePtr); + if (node.category == NodeCategory::dyninput) + InvalidateSuccessors(node); ScheduleSuccessors(node); } @@ -209,10 +274,17 @@ void SingleThreadedGraph::DoTransaction(TransactionFlags flags, F&& transactionC if (! scheduledNodes_.IsEmpty()) Propagate(); - ClearBufferedNodes(); + if (!scheduledLinkNodes_.empty()) + UpdateLinkNodes(); } -void SingleThreadedGraph::Propagate() +template +void ReactiveGraph::EnqueueTransaction(TransactionFlags flags, F&& transactionCallback) +{ + transactionQueue_.Push(flags, std::forward(transactionCallback)); +} + +void ReactiveGraph::Propagate() { while (scheduledNodes_.FetchNext()) { @@ -230,29 +302,27 @@ void SingleThreadedGraph::Propagate() continue; } - auto result = nodePtr->Update(0); + int successorCount = node.successors.size(); - if (result == UpdateResult::changed) + if (nodePtr->Update(0, successorCount) == UpdateResult::changed) { - if (IsBitmaskSet(node.flags, NodeFlags::buffered)) - pendingBufferedNodes_.push_back(nodePtr); - ScheduleSuccessors(node); } - else if (result == UpdateResult::shifted) - { - // Re-schedule this node - InvalidateSuccessors(node); - scheduledNodes_.Push(nodeId, node.level); - continue; - } node.queued = false; } } } -void SingleThreadedGraph::ScheduleSuccessors(NodeData& node) +void ReactiveGraph::UpdateLinkNodes() +{ + for (const auto& x : scheduledLinkNodes_) + { + + } +} + +void ReactiveGraph::ScheduleSuccessors(NodeData& node) { for (NodeId succId : node.successors) { @@ -261,12 +331,16 @@ void SingleThreadedGraph::ScheduleSuccessors(NodeData& node) if (!succ.queued) { succ.queued = true; - scheduledNodes_.Push(succId, succ.level); + + if (node.category != NodeCategory::link) + scheduledNodes_.Push(succId, succ.level); + else + scheduledLinkNodes_.push_back(succId); } } } -void SingleThreadedGraph::InvalidateSuccessors(NodeData& node) +void ReactiveGraph::InvalidateSuccessors(NodeData& node) { for (NodeId succId : node.successors) { @@ -277,14 +351,7 @@ void SingleThreadedGraph::InvalidateSuccessors(NodeData& node) } } -void SingleThreadedGraph::ClearBufferedNodes() -{ - for (IReactiveNode* nodePtr : pendingBufferedNodes_) - nodePtr->ClearBuffer(); - pendingBufferedNodes_.clear(); -} - -bool SingleThreadedGraph::TopoQueue::FetchNext() +bool ReactiveGraph::TopoQueue::FetchNext() { // Throw away previous values nextData_.clear(); @@ -310,6 +377,68 @@ bool SingleThreadedGraph::TopoQueue::FetchNext() return !nextData_.empty(); } +void TransactionQueue::ProcessQueue() +{ + for (;;) + { + size_t popCount = ProcessNextBatch(); + if (count_.fetch_sub(popCount) == popCount) + return; + } +} + +size_t TransactionQueue::ProcessNextBatch() +{ + StoredTransaction curTransaction; + size_t popCount = 0; + bool canMerge = false; + bool skipPop = false; + bool isDone = false; + + // Outer loop. One transaction per iteration. + for (;;) + { + if (!skipPop) + { + if (transactions_.try_pop(curTransaction)) + return popCount; + + canMerge = IsBitmaskSet(curTransaction.flags, TransactionFlags::allow_merging); + ++popCount; + } + else + { + skipPop = false; + } + + graph_.DoTransaction([&] + { + curTransaction.callback(); + + if (canMerge) + { + // Inner loop. Mergeable transactions are merged + for (;;) + { + if (transactions_.try_pop(curTransaction)) + return; + + canMerge = IsBitmaskSet(curTransaction.flags, TransactionFlags::allow_merging); + ++popCount; + + if (!canMerge) + { + skipPop = true; + return; + } + + curTransaction.callback(); + } + } + }); + } +} + /****************************************/ REACT_IMPL_END /***************************************/ #endif // REACT_DETAIL_GRAPH_PROPAGATIONST_H_INCLUDED \ No newline at end of file diff --git a/include/react/detail/graph/SignalNodes.h b/include/react/detail/graph/SignalNodes.h index 30128a3e..2bdd3eac 100644 --- a/include/react/detail/graph/SignalNodes.h +++ b/include/react/detail/graph/SignalNodes.h @@ -12,7 +12,9 @@ #include "react/detail/Defs.h" #include +#include #include +#include #include "GraphBase.h" @@ -37,13 +39,13 @@ class SignalNode : public NodeBase SignalNode(const SignalNode&) = delete; SignalNode& operator=(const SignalNode&) = delete; - explicit SignalNode(const std::shared_ptr& graphPtr) : + explicit SignalNode(const std::shared_ptr& graphPtr) : SignalNode::NodeBase( graphPtr ), value_( ) { } template - SignalNode(const std::shared_ptr& graphPtr, T&& value) : + SignalNode(const std::shared_ptr& graphPtr, T&& value) : SignalNode::NodeBase( graphPtr ), value_( std::forward(value) ) { } @@ -54,9 +56,6 @@ class SignalNode : public NodeBase const S& Value() const { return value_; } - virtual void ClearBuffer() override - { }; - private: S value_; }; @@ -68,13 +67,13 @@ template class VarSignalNode : public SignalNode { public: - explicit VarSignalNode(const std::shared_ptr& graphPtr) : + explicit VarSignalNode(const std::shared_ptr& graphPtr) : VarSignalNode::SignalNode( graphPtr ), newValue_( ) - { this->RegisterMe(NodeFlags::input); } + { this->RegisterMe(NodeCategory::input); } template - VarSignalNode(const std::shared_ptr& graphPtr, T&& value) : + VarSignalNode(const std::shared_ptr& graphPtr, T&& value) : VarSignalNode::SignalNode( graphPtr, std::forward(value) ), newValue_( value ) { this->RegisterMe(); } @@ -88,7 +87,7 @@ class VarSignalNode : public SignalNode virtual int GetDependencyCount() const override { return 0; } - virtual UpdateResult Update(TurnId turnId) override + virtual UpdateResult Update(TurnId turnId, int successorCount) override { if (isInputAdded_) { @@ -162,7 +161,7 @@ class SignalFuncNode : public SignalNode { public: template - SignalFuncNode(const std::shared_ptr& graphPtr, FIn&& func, const std::shared_ptr>& ... deps) : + SignalFuncNode(const std::shared_ptr& graphPtr, FIn&& func, const std::shared_ptr>& ... deps) : SignalFuncNode::SignalNode( graphPtr, func(deps->Value() ...) ), func_( std::forward(func) ), depHolder_( deps ... ) @@ -183,7 +182,7 @@ class SignalFuncNode : public SignalNode virtual int GetDependencyCount() const override { return sizeof...(TDeps); } - virtual UpdateResult Update(TurnId turnId) override + virtual UpdateResult Update(TurnId turnId, int successorCount) override { bool changed = false; @@ -208,54 +207,43 @@ class SignalFuncNode : public SignalNode }; /////////////////////////////////////////////////////////////////////////////////////////////////// -/// FlattenNode +/// SignalSlotNode /////////////////////////////////////////////////////////////////////////////////////////////////// -template -class SignalFlattenNode : public SignalNode +template +class SignalSlotNode : public SignalNode { public: - SignalFlattenNode(const std::shared_ptr& graphPtr, const std::shared_ptr>& outer, const std::shared_ptr>& inner) : - SignalFlattenNode::SignalNode( graphPtr, inner->Value() ), - outer_( outer ), - inner_( inner ) + SignalSlotNode(const std::shared_ptr& graphPtr, const std::shared_ptr>& dep) : + SignalSlotNode::SignalNode( graphPtr, dep->Value() ), + slotInput_( *this, dep ) { - this->RegisterMe(NodeFlags::dynamic); - this->AttachToMe(outer->GetNodeId()); - this->AttachToMe(inner->GetNodeId()); + slotInput_.nodeId = GraphPtr()->RegisterNode(&slotInput_, NodeCategory::dyninput); + this->RegisterMe(); + + this->AttachToMe(slotInput_.nodeId); + this->AttachToMe(dep->GetNodeId()); } - ~SignalFlattenNode() + ~SignalSlotNode() { - this->DetachFromMe(inner->GetNodeId()); - this->DetachFromMe(outer->GetNodeId()); + this->DetachFromMe(slotInput_.dep->GetNodeId()); + this->DetachFromMe(slotInput_.nodeId); + this->UnregisterMe(); + GraphPtr()->UnregisterNode(slotInput_.nodeId); } virtual const char* GetNodeType() const override - { return "SignalFlatten"; } + { return "SignalSlot"; } virtual int GetDependencyCount() const override { return 2; } - virtual UpdateResult Update(TurnId turnId) override + virtual UpdateResult Update(TurnId turnId, int successorCount) override { - auto newInner = GetNodePtr(outer_->Value()); - - if (newInner != inner_) + if (! (this->Value() == slotInput_.dep->Value())) { - // Topology has been changed - auto oldInner = inner_; - inner_ = newInner; - - this->DynamicDetachFromMe(oldInner->GetNodeId(), 0); - this->DynamicAttachToMe(newInner->GetNodeId(), 0); - - return UpdateResult::shifted; - } - - if (! Equals(this->Value(), inner_->Value())) - { - this->Value() = inner_->Value(); + this->Value() = slotInput_.dep->Value(); return UpdateResult::changed; } else @@ -264,9 +252,142 @@ class SignalFlattenNode : public SignalNode } } + void SetInput(const std::shared_ptr>& newInput) + { slotInput_.newDep = newInput; } + + NodeId GetInputNodeId() const + { return slotInput_.nodeId; } + +private: + struct VirtualInputNode : public IReactiveNode + { + VirtualInputNode(SignalSlotNode& parentIn, const std::shared_ptr>& depIn) : + parent( parentIn ), + dep( depIn ) + { } + + virtual const char* GetNodeType() const override + { return "SignalSlotVirtualInput"; } + + virtual int GetDependencyCount() const override + { return 0; } + + virtual UpdateResult Update(TurnId turnId, int successorCount) override + { + if (dep != newDep) + { + parent.DynamicDetachFromMe(dep->GetNodeId(), 0); + parent.DynamicAttachToMe(newDep->GetNodeId(), 0); + + dep = std::move(newDep); + return UpdateResult::changed; + } + else + { + newDep.reset(); + return UpdateResult::unchanged; + } + } + + SignalSlotNode& parent; + + NodeId nodeId; + + std::shared_ptr> dep; + std::shared_ptr> newDep; + }; + + VirtualInputNode slotInput_; +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// SignalBridgeNode +/////////////////////////////////////////////////////////////////////////////////////////////////// +template +class SignalLinkNode : public SignalNode +{ +public: + SignalLinkNode(const std::shared_ptr& graphPtr, const std::shared_ptr& srcGraphPtr, const std::shared_ptr>& dep) : + SignalLinkNode::SignalNode( graphPtr, dep->Value() ), + linkOutput_( *this, srcGraphPtr, dep ) + { + slotInput_.nodeId = GraphPtr()->RegisterNode(&linkOutput_, NodeCategory::dyninput); + this->RegisterMe(); + + this->AttachToMe(slotInput_.nodeId); + this->AttachToMe(dep->GetNodeId()); + } + + ~SignalLinkNode() + { + this->DetachFromMe(slotInput_.dep->GetNodeId()); + this->DetachFromMe(slotInput_.nodeId); + + this->UnregisterMe(); + GraphPtr()->UnregisterNode(slotInput_.nodeId); + } + + virtual const char* GetNodeType() const override + { return "SignalLink"; } + + virtual int GetDependencyCount() const override + { return 2; } + + virtual UpdateResult Update(TurnId turnId, int successorCount) override + { + {// outputDataMutex + std::lock_guard lock(linkOutput_.outputDataMutex); + this->Value() = std::move(linkOutput_.outputData.front()); + linkOutput_.outputData.pop(); + }// ~outputDataMutex + + return UpdateResult::changed; + } + private: - std::shared_ptr> outer_; - std::shared_ptr> inner_; + struct VirtualOutputNode : public ILinkOutputNode + { + VirtualOutputNode(SignalSlotNode& parentIn, const std::shared_ptr& srcGraphPtrIn, const std::shared_ptr>& depIn) : + parent( parentIn ), + srcGraphPtr(srcGraphPtrIn), + dep( depIn ) + { } + + virtual const char* GetNodeType() const override + { return "SignalLinkVirtualOutput"; } + + virtual int GetDependencyCount() const override + { return 1; } + + virtual UpdateResult Update(TurnId turnId, int successorCount) override + { + {// outputDataMutex + std::lock_guard lock(outputDataMutex); + outputData.push(dep->Value()); + }// ~outputDataMutex + + return UpdateResult::changed; + } + + virtual void CollectOutput(LinkOutputList& output) override + { output.emplace_back(srcGraphPtr.get(), &parent); } + + SignalSlotNode& parent; + + NodeId nodeId; + + std::shared_ptr> dep; + + std::mutex outputDataMutex; + + std::queue> outputData; + + std::shared_ptr srcGraphPtr; + }; + + VirtualOutputNode linkOutput_; + + }; /****************************************/ REACT_IMPL_END /***************************************/ From a7ae030ef76f7c2de5bba1ec5d1014671c69500c Mon Sep 17 00:00:00 2001 From: schlangster Date: Fri, 9 Dec 2016 18:13:31 +0100 Subject: [PATCH 36/75] Progress... --- examples/src/Main.cpp | 245 ++++++++++++++++++-- include/react/API.h | 12 +- include/react/Event.h | 221 +++++++++++++++--- include/react/Group.h | 2 +- include/react/Observer.h | 89 ++++++-- include/react/Signal.h | 246 +++++++++++++++++---- include/react/detail/IReactiveGraph.h | 8 +- include/react/detail/graph/EventNodes.h | 101 ++++++++- include/react/detail/graph/PropagationST.h | 63 ++++-- include/react/detail/graph/SignalNodes.h | 90 ++++---- 10 files changed, 888 insertions(+), 189 deletions(-) diff --git a/examples/src/Main.cpp b/examples/src/Main.cpp index 89f61f07..62d5c079 100644 --- a/examples/src/Main.cpp +++ b/examples/src/Main.cpp @@ -4,37 +4,248 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -//#define REACT_ENABLE_LOGGING +#include +#include +#include +#include -#include "react/Domain.h" #include "react/Signal.h" #include "react/Event.h" #include "react/Algorithm.h" +#include "react/Observer.h" -#include "tbb/tick_count.h" +using namespace react; -#include +template +T Multiply(T a, T b) +{ + return a * b; +} -using namespace std; -using namespace react; +template void PrintValue(T v) +{ + printf("Value: %d\n", v); +} + +template void PrintArea(T v) +{ + printf("Area: %d\n", v); +} + +template void PrintVolume(T v) +{ + printf("Volume: %d\n", v); +} -void testme() +template void PrintEvents(EventRange evts) { - // Note: This project exists as a sandbox where I occasionally stage new examples. - // Currently it's empty. + printf("Processing events...\n"); + + for (const auto& e : evts) + printf(" Event: %d\n", e); +} + +template bool FilterFunc(T v) +{ + return v > 10; +} + +int main2() +{ + ReactiveGroup<> group; + + { + // Signals + VarSignal x{ group, 0 }; + VarSignal y{ group, 0 }; + VarSignal z{ group, 0 }; + + Signal area{ Multiply, x, y }; + Signal volume{ Multiply, area, z }; + + Observer<> areaObs{ PrintArea, area }; + Observer<> volumeObs{ PrintVolume, volume }; + + x.Set(2); // a: 0, v: 0 + y.Set(2); // a: 4, v: 0 + z.Set(2); // a: 4, v: 8 + + group.DoTransaction([&] + { + x <<= 100; + y <<= 3; + y <<= 4; + }); + + // a: 400, v: 800 + } + + { + // Events + EventSource button1{ group }; + EventSource button2{ group }; + + Event anyButton = Merge(button1, button2); + Event filtered = Filter(FilterFunc, anyButton); + + Observer<> eventObs{ PrintEvents, anyButton }; + + button1.Emit(1); + button2.Emit(2); + + group.DoTransaction([&] + { + for (int i=0; i<10; ++i) + button1.Emit(42); + }); + } + + { + // Dynamic signals + VarSignal s1{ group, 10 }; + VarSignal s2{ group, 22 }; + + SignalSlot slot{ s1 }; + + Observer<> areaObs{ PrintValue, slot }; + + s1.Set(42); + + slot.Set(s2); + + s2.Set(667); + } + + { + ReactiveGroup<> group1; + ReactiveGroup<> group2; + + VarSignal s1{ group1, 10 }; + VarSignal s2{ group2, 11 }; + + Signal v{ Multiply, s1, s2 }; + + Observer<> obs{ PrintValue, v }; + + s1.Set(555); + + std::this_thread::sleep_for(std::chrono::seconds(5)); + } + + { + ReactiveGroup<> group1; + ReactiveGroup<> group2; + + EventSource e1{ group1 }; + EventSource e2{ group2 }; + + auto merged = Merge(group2, e1, e2); + + auto joined = Join(e1, e2); + auto joined2 = Join(group1, e1, e2); + + Observer<> eventObs{ PrintEvents, merged }; + + e1.Emit(222); + + std::this_thread::sleep_for(std::chrono::seconds(5)); + } + + return 0; } int main() { - testme(); + ReactiveGroup<> group; + + VarSignal a{ }; + VarSignal b{ }; + +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +/*int main2() +{ + ReactiveGroup<> group1; + ReactiveGroup<> group2; + ReactiveGroup<> group3; + + VarSignal x{ 0, group1 }; + VarSignal y{ 0, group2 }; + VarSignal z{ 0, group3 }; + + Signal area{ Multiply, x, y }; + Signal volume{ Multiply, area, z }; + + Observer<> obs{ PrintAreaAndVolume, area, volume }; + + Signal> volumeHistory = Iterate>( vector{ }, PushToVector, Monitor(volume)); + + x <<= 2; + y <<= 2; + z <<= 2; + + group.DoTransaction([&] + { + x <<= 100; + y <<= 200; + z <<= 300; + }); + + obs.Cancel(); + + x <<= 42; + + printf("History:\n"); + for (auto t : volumeHistory.Value()) + printf("%d ", t); + printf("\n"); + + return 0; +} + + +int main3() +{ + using namespace std; + using namespace react; + + ReactiveGroup<> group1; + ReactiveGroup<> group2; + + auto sig1 = VarSignal( 10, group1 ); -#ifdef REACT_ENABLE_LOGGING - std::ofstream logfile; - logfile.open("log.txt"); + auto link1 = SignalLink( sig1, group2 ); + auto link2 = SignalLink( sig1, group2 ); - D::Log().Write(logfile); - logfile.close(); -#endif + sig1.Set(10); return 0; -} \ No newline at end of file +}*/ \ No newline at end of file diff --git a/include/react/API.h b/include/react/API.h index 928d1007..79a44241 100644 --- a/include/react/API.h +++ b/include/react/API.h @@ -29,12 +29,6 @@ enum ReferencePolicy weak }; -enum ThreadingPolicy -{ - sequential, - concurrent -}; - enum class WeightHint { automatic, @@ -68,6 +62,9 @@ class VarSignalBase; template class SignalSlotBase; +template +class SignalLinkBase; + template class Signal; @@ -77,6 +74,9 @@ class VarSignal; template class SignalSlot; +template +class SignalLink; + // Events enum class Token; diff --git a/include/react/Event.h b/include/react/Event.h index 2c9222fd..89bcc0c8 100644 --- a/include/react/Event.h +++ b/include/react/Event.h @@ -19,6 +19,12 @@ #include "react/detail/graph/EventNodes.h" +/***************************************/ REACT_IMPL_BEGIN /**************************************/ + +struct PrivateEventLinkNodeInterface; + +/****************************************/ REACT_IMPL_END /***************************************/ + /*****************************************/ REACT_BEGIN /*****************************************/ /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -32,7 +38,7 @@ class EventBase public: // Private node ctor - EventBase(REACT_IMPL::NodeCtorTag, std::shared_ptr&& nodePtr) : + EventBase(REACT_IMPL::CtorTag, std::shared_ptr&& nodePtr) : nodePtr_( std::move(nodePtr) ) { } @@ -128,13 +134,10 @@ class EventSourceBase : public EventBase EventSourceBase(EventSourceBase&& other) = default; EventSourceBase& operator=(EventSourceBase&& other) = default; - template - auto CreateSourceNode(const TGroup& group) -> decltype(auto) + auto CreateSourceNode(const std::shared_ptr& graphPtr) -> decltype(auto) { - using REACT_IMPL::PrivateReactiveGroupInterface; using SrcNodeType = REACT_IMPL::EventSourceNode; - - return std::make_shared(PrivateReactiveGroupInterface::GraphPtr(group)); + return std::make_shared(graphPtr); } private: @@ -177,7 +180,7 @@ class EventSlotBase : public EventBase EventSlotBase(EventSlotBase&&) = default; EventSlotBase& operator=(EventSlotBase&&) = default; - auto CreateSlotNode(const EventBase& input, const ReactiveGroupBase& group) -> decltype(auto) + auto CreateSlotNode(const std::shared_ptr& graphPtr, const EventBase& input) -> decltype(auto) { using REACT_IMPL::PrivateNodeInterface; using REACT_IMPL::PrivateReactiveGroupInterface; @@ -202,6 +205,38 @@ class EventSlotBase : public EventBase } }; +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// EventLinkBase +/////////////////////////////////////////////////////////////////////////////////////////////////// +template +class EventLinkBase : public EventBase +{ +public: + using EventBase::EventBase; + +protected: + EventLinkBase() = default; + + EventLinkBase(const EventLinkBase&) = default; + EventLinkBase& operator=(const EventLinkBase&) = default; + + EventLinkBase(EventLinkBase&&) = default; + EventLinkBase& operator=(EventLinkBase&&) = default; + + static auto CreateLinkNode(const std::shared_ptr& graphPtr, const EventBase& input) -> decltype(auto) + { + using REACT_IMPL::PrivateNodeInterface; + using REACT_IMPL::PrivateReactiveGroupInterface; + using EventNodeType = REACT_IMPL::EventLinkNode; + + auto node = std::make_shared(graphPtr, PrivateNodeInterface::GraphPtr(input), PrivateNodeInterface::NodePtr(input)); + node->SetWeakSelfPtr(std::weak_ptr{ node }); + return node; + } + + friend struct REACT_IMPL::PrivateEventLinkNodeInterface; +}; + /////////////////////////////////////////////////////////////////////////////////////////////////// /// Event /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -223,12 +258,22 @@ class Event : public EventBase template Event(F&& func, const EventBase& dep) : - Event::EventBase( REACT_IMPL::NodeCtorTag{ }, CreateProcessingNode(std::forward(func), dep) ) + Event::EventBase( REACT_IMPL::CtorTag{ }, CreateProcessingNode(std::forward(func), dep) ) + { } + + template + Event(const ReactiveGroupBase& group, F&& func, const EventBase& dep) : + Event::EventBase( REACT_IMPL::CtorTag{ }, CreateProcessingNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), std::forward(func), dep) ) { } template Event(F&& func, const EventBase& dep, const SignalBase& ... signals) : - Event::EventBase( REACT_IMPL::NodeCtorTag{ }, CreateSyncedProcessingNode(std::forward(func), dep, signals ...) ) + Event::EventBase( REACT_IMPL::CtorTag{ }, CreateSyncedProcessingNode(std::forward(func), dep, signals ...) ) + { } + + template + Event(const ReactiveGroupBase& group, F&& func, const EventBase& dep, const SignalBase& ... signals) : + Event::EventBase( REACT_IMPL::CtorTag{ }, CreateSyncedProcessingNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), std::forward(func), dep, signals ...) ) { } }; @@ -257,12 +302,22 @@ class Event : public EventBase template Event(F&& func, const EventBase& dep) : - Event::EventBase( REACT_IMPL::NodeCtorTag{ }, CreateProcessingNode(std::forward(func), dep) ) + Event::EventBase( REACT_IMPL::CtorTag{ }, CreateProcessingNode(std::forward(func), dep) ) + { } + + template + Event(const ReactiveGroupBase& group, F&& func, const EventBase& dep) : + Event::EventBase( REACT_IMPL::CtorTag{ }, CreateProcessingNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), std::forward(func), dep) ) { } template Event(F&& func, const EventBase& dep, const SignalBase& ... signals) : - Event::EventBase( REACT_IMPL::NodeCtorTag{ }, CreateSyncedProcessingNode(std::forward(func), dep, signals ...) ) + Event::EventBase( REACT_IMPL::CtorTag{ }, CreateSyncedProcessingNode(std::forward(func), dep, signals ...) ) + { } + + template + Event(const ReactiveGroupBase& group, F&& func, const EventBase& dep, const SignalBase& ... signals) : + Event::EventBase( REACT_IMPL::CtorTag{ }, CreateSyncedProcessingNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), std::forward(func), dep, signals ...) ) { } }; @@ -286,9 +341,8 @@ class EventSource : public EventSourceBase EventSource& operator=(EventSource&&) = default; // Construct event source - template - explicit EventSource(const TGroup& group) : - EventSource::EventSourceBase( REACT_IMPL::NodeCtorTag{ }, CreateSourceNode(group) ) + explicit EventSource(const ReactiveGroupBase& group) : + EventSource::EventSourceBase( REACT_IMPL::CtorTag{ }, CreateSourceNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group)) ) { } }; @@ -309,9 +363,8 @@ class EventSource : public EventSourceBase EventSource& operator=(EventSource&&) = default; // Construct event source - template - explicit EventSource(const TGroup& group) : - EventSource::EventSourceBase( REACT_IMPL::NodeCtorTag{ }, CreateSourceNode(group) ) + explicit EventSource(const ReactiveGroupBase& group) : + EventSource::EventSourceBase( REACT_IMPL::CtorTag{ }, CreateSourceNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group)) ) { } // Construct from unique @@ -344,8 +397,8 @@ class EventSlot : public EventSlotBase EventSlot& operator=(EventSlot&&) = default; // Construct with value - EventSlot(const EventBase& input, const ReactiveGroupBase& group) : - EventSlot::EventSlotBase( REACT_IMPL::NodeCtorTag{ }, CreateSlotNode(input, group) ) + EventSlot(const ReactiveGroupBase& group, const EventBase& input) : + EventSlot::EventSlotBase( REACT_IMPL::CtorTag{ }, CreateSlotNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), input) ) { } }; @@ -375,21 +428,43 @@ class EventSlot : public EventSlotBase { EventSlot::EventSlotBase::operator=(std::move(other)); return *this; } // Construct with value - EventSlot(const SignalBase& input, const ReactiveGroupBase& group) : - EventSlot::EventSlotBase( REACT_IMPL::NodeCtorTag{ }, CreateSlotNode(input, group) ) + EventSlot(const ReactiveGroupBase& group, const SignalBase& input) : + EventSlot::EventSlotBase( REACT_IMPL::CtorTag{ }, CreateSlotNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), input) ) { } }; /////////////////////////////////////////////////////////////////////////////////////////////////// /// Merge /////////////////////////////////////////////////////////////////////////////////////////////////// +template +auto Merge(const ReactiveGroupBase& group, const EventBase& dep1, const EventBase& ... deps) -> decltype(auto) +{ + using REACT_IMPL::EventMergeNode; + using REACT_IMPL::PrivateEventLinkNodeInterface; + using REACT_IMPL::PrivateReactiveGroupInterface; + using REACT_IMPL::CtorTag; + + static_assert(sizeof...(Us) > 0, "Merge requires at least 2 inputs."); + + // If supplied, use merge type, otherwise default to common type. + using E = typename std::conditional< + std::is_same::value, + typename std::common_type::type, + T>::type; + + const auto& graphPtr = PrivateReactiveGroupInterface::GraphPtr(group); + + return Event( CtorTag{ }, std::make_shared>( + graphPtr, PrivateEventLinkNodeInterface::GetLocalEventNodePtr(graphPtr, dep1), PrivateEventLinkNodeInterface::GetLocalEventNodePtr(graphPtr, deps) ...)); +} + template auto Merge(const EventBase& dep1, const EventBase& ... deps) -> decltype(auto) { using REACT_IMPL::EventMergeNode; - using REACT_IMPL::GetCheckedGraphPtr; + using REACT_IMPL::PrivateEventLinkNodeInterface; using REACT_IMPL::PrivateNodeInterface; - using REACT_IMPL::NodeCtorTag; + using REACT_IMPL::CtorTag; static_assert(sizeof...(Us) > 0, "Merge requires at least 2 inputs."); @@ -399,15 +474,24 @@ auto Merge(const EventBase& dep1, const EventBase& ... deps) -> decltype typename std::common_type::type, T>::type; - const auto& graphPtr = GetCheckedGraphPtr(dep1, deps ...); + const auto& graphPtr = PrivateNodeInterface::GraphPtr(dep1); - return Event( NodeCtorTag{ }, std::make_shared>( - graphPtr, PrivateNodeInterface::NodePtr(dep1), PrivateNodeInterface::NodePtr(deps) ...)); + return Event( CtorTag{ }, std::make_shared>( + graphPtr, PrivateEventLinkNodeInterface::GetLocalEventNodePtr(graphPtr, dep1), PrivateEventLinkNodeInterface::GetLocalEventNodePtr(graphPtr, deps) ...)); } /////////////////////////////////////////////////////////////////////////////////////////////////// /// Filter /////////////////////////////////////////////////////////////////////////////////////////////////// +template +auto Filter(const ReactiveGroupBase& group, F&& pred, const EventBase& dep) -> Event +{ + auto filterFunc = [capturedPred = std::forward(pred)] (EventRange inRange, EventSink out) + { std::copy_if(inRange.begin(), inRange.end(), out, capturedPred); }; + + return Event(group, std::move(filterFunc), dep); +} + template auto Filter(F&& pred, const EventBase& dep) -> Event { @@ -417,6 +501,19 @@ auto Filter(F&& pred, const EventBase& dep) -> Event return Event(std::move(filterFunc), dep); } +template +auto Filter(const ReactiveGroupBase& group, F&& pred, const EventBase& dep, const SignalBase& ... signals) -> Event +{ + auto filterFunc = [capturedPred = std::forward(pred)] (EventRange inRange, EventSink out, const Us& ... values) + { + for (const auto& v : inRange) + if (capturedPred(v, values ...)) + *out++ = v; + }; + + return Event(group, std::move(filterFunc), dep, signals ...); +} + template auto Filter(F&& pred, const EventBase& dep, const SignalBase& ... signals) -> Event { @@ -433,6 +530,15 @@ auto Filter(F&& pred, const EventBase& dep, const SignalBase& ... signals /////////////////////////////////////////////////////////////////////////////////////////////////// /// Transform /////////////////////////////////////////////////////////////////////////////////////////////////// +template +auto Transform(const ReactiveGroupBase& group, F&& op, const EventBase& dep) -> Event +{ + auto transformFunc = [capturedOp = std::forward(op)] (EventRange inRange, EventSink out) + { std::transform(inRange.begin(), inRange.end(), out, capturedOp); }; + + return Event(group, std::move(transformFunc), dep); +} + template auto Transform(F&& op, const EventBase& dep) -> Event { @@ -442,6 +548,18 @@ auto Transform(F&& op, const EventBase& dep) -> Event return Event(std::move(transformFunc), dep); } +template +auto Transform(const ReactiveGroupBase& group, F&& op, const EventBase& dep, const SignalBase& ... signals) -> Event +{ + auto transformFunc = [capturedOp = std::forward(pred)] (EventRange inRange, EventSink out, const Vs& ... values) + { + for (const auto& v : inRange) + *out++ = capturedPred(v, values ...); + }; + + return Event(group, std::move(transformFunc), dep, signals ...); +} + template auto Transform(F&& op, const EventBase& dep, const SignalBase& ... signals) -> Event { @@ -468,21 +586,38 @@ auto Flatten(const Signal>& outer) -> Events /////////////////////////////////////////////////////////////////////////////////////////////////// /// Join /////////////////////////////////////////////////////////////////////////////////////////////////// -template -auto Join(const EventBase& ... deps) -> Event, unique> +template +auto Join(const ReactiveGroupBase& group, const EventBase& dep1, const EventBase& ... deps) -> Event, unique> +{ + using REACT_IMPL::EventJoinNode; + using REACT_IMPL::PrivateReactiveGroupInterface; + using REACT_IMPL::PrivateEventLinkNodeInterface; + using REACT_IMPL::CtorTag; + + static_assert(sizeof...(Us) > 0, "Join requires at least 2 inputs."); + + // If supplied, use merge type, otherwise default to common type. + const auto& graphPtr = PrivateReactiveGroupInterface::GraphPtr(group); + + return Event, unique>( CtorTag{ }, std::make_shared>( + graphPtr, PrivateEventLinkNodeInterface::GetLocalEventNodePtr(graphPtr, dep1), PrivateEventLinkNodeInterface::GetLocalEventNodePtr(graphPtr, deps) ...)); +} + +template +auto Join(const EventBase& dep1, const EventBase& ... deps) -> Event, unique> { using REACT_IMPL::EventJoinNode; - using REACT_IMPL::GetCheckedGraphPtr; using REACT_IMPL::PrivateNodeInterface; - using REACT_IMPL::NodeCtorTag; + using REACT_IMPL::PrivateEventLinkNodeInterface; + using REACT_IMPL::CtorTag; - static_assert(sizeof...(Ts) > 1, "Join requires at least 2 inputs."); + static_assert(sizeof...(Us) > 0, "Join requires at least 2 inputs."); // If supplied, use merge type, otherwise default to common type. - const auto& graphPtr = GetCheckedGraphPtr(deps ...); + const auto& graphPtr = PrivateNodeInterface::GraphPtr(dep1); - return Event, unique>( NodeCtorTag{ }, std::make_shared>( - graphPtr, PrivateNodeInterface::NodePtr(deps) ...)); + return Event, unique>( CtorTag{ }, std::make_shared>( + graphPtr, PrivateEventLinkNodeInterface::GetLocalEventNodePtr(graphPtr, dep1), PrivateEventLinkNodeInterface::GetLocalEventNodePtr(graphPtr, deps) ...)); } /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -512,6 +647,24 @@ bool Equals(const EventBase& lhs, const EventBase& rhs) return lhs.Equals(rhs); } +struct PrivateEventLinkNodeInterface +{ + template + static auto GetLocalEventNodePtr(const std::shared_ptr& targetGraph, const EventBase& dep) -> std::shared_ptr> + { + const std::shared_ptr& sourceGraph = PrivateNodeInterface::GraphPtr(dep); + + if (sourceGraph == targetGraph) + { + return PrivateNodeInterface::NodePtr(dep); + } + else + { + return EventLinkBase::CreateLinkNode(targetGraph, dep); + } + } +}; + /****************************************/ REACT_IMPL_END /***************************************/ #endif // REACT_EVENT_H_INCLUDED \ No newline at end of file diff --git a/include/react/Group.h b/include/react/Group.h index 4ab5d2af..ac5c1b91 100644 --- a/include/react/Group.h +++ b/include/react/Group.h @@ -23,7 +23,7 @@ struct PrivateReactiveGroupInterface; struct PrivateConcurrentReactiveGroupInterface; -struct NodeCtorTag { }; +struct CtorTag { }; /****************************************/ REACT_IMPL_END /***************************************/ diff --git a/include/react/Observer.h b/include/react/Observer.h index 9d5c6409..590c5baa 100644 --- a/include/react/Observer.h +++ b/include/react/Observer.h @@ -56,38 +56,51 @@ class ObserverBase { return nodePtr_; } template - auto CreateSignalObserverNode(F&& func, const SignalBase& dep1, const SignalBase& ... deps) -> decltype(auto) + auto CreateSignalObserverNode(const std::shared_ptr& graphPtr, F&& func, const SignalBase& dep1, const SignalBase& ... deps) -> decltype(auto) { - using REACT_IMPL::GetCheckedGraphPtr; - using REACT_IMPL::PrivateNodeInterface; + using REACT_IMPL::PrivateSignalLinkNodeInterface; using ObsNodeType = REACT_IMPL::SignalObserverNode::type, T1, Ts ...>; return std::make_shared( - GetCheckedGraphPtr(dep1, deps ...), + graphPtr, std::forward(func), - PrivateNodeInterface::NodePtr(dep1), PrivateNodeInterface::NodePtr(deps) ...); + PrivateSignalLinkNodeInterface::GetLocalSignalNodePtr(graphPtr, dep1), PrivateSignalLinkNodeInterface::GetLocalSignalNodePtr(graphPtr, deps) ...); } - template - auto CreateEventObserverNode(F&& func, const EventBase& dep) -> decltype(auto) + template + auto CreateSignalObserverNode(F&& func, const SignalBase& dep1, const SignalBase& ... deps) -> decltype(auto) { using REACT_IMPL::PrivateNodeInterface; + return CreateSignalObserverNode(PrivateNodeInterface::GraphPtr(dep1), std::forward(func), dep1, deps ...); + } + + template + auto CreateEventObserverNode(const std::shared_ptr& graphPtr, F&& func, const EventBase& dep) -> decltype(auto) + { + using REACT_IMPL::PrivateEventLinkNodeInterface; using ObsNodeType = REACT_IMPL::EventObserverNode::type, T>; - return std::make_shared(PrivateNodeInterface::GraphPtr(dep), std::forward(func), PrivateNodeInterface::NodePtr(dep)); + return std::make_shared(graphPtr, std::forward(func), PrivateEventLinkNodeInterface::GetLocalEventNodePtr(graphPtr, dep)); + } + + template + auto CreateEventObserverNode(F&& func, const EventBase& dep) -> decltype(auto) + { + using REACT_IMPL::PrivateNodeInterface; + return CreateSignalObserverNode(PrivateNodeInterface::GraphPtr(dep1), std::forward(func), dep1, deps ...); } template auto CreateSyncedEventObserverNode(F&& func, const EventBase& dep, const SignalBase& ... syncs) -> decltype(auto) { - using REACT_IMPL::GetCheckedGraphPtr; using REACT_IMPL::PrivateNodeInterface; + using REACT_IMPL::PrivateSignalLinkNodeInterface; using ObsNodeType = REACT_IMPL::SyncedEventObserverNode::type, T, Us ...>; + const auto& graphPtr = PrivateNodeInterface::GraphPtr(dep); + return std::make_shared( - GetCheckedGraphPtr(dep, syncs ...), - std::forward(func), - PrivateNodeInterface::NodePtr(dep), PrivateNodeInterface::NodePtr(syncs) ...); + graphPtr, std::forward(func), PrivateSignalLinkNodeInterface::GetLocalSignalNodePtr(graphPtr, dep), PrivateSignalLinkNodeInterface::GetLocalSignalNodePtr(graphPtr, syncs) ...); } private: @@ -113,23 +126,41 @@ class Observer : public ObserverBase Observer(Observer&&) = default; Observer& operator=(Observer&&) = default; - // Construct signal observer + // Construct signal observer with implicit group template Observer(F&& func, const SignalBase& ... subjects) : Observer::ObserverBase( CreateSignalObserverNode(std::forward(func), subjects ...) ) { } - // Construct event observer + // Construct signal observer with explicit group + template + Observer(const ReactiveGroupBase& group, F&& func, const SignalBase& ... subjects) : + Observer::ObserverBase( CreateSignalObserverNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), std::forward(func), subjects ...) ) + { } + + // Construct event observer with implicit group template Observer(F&& func, const EventBase& subject) : - Observer::ObserverBase( CreateEventObserverNode(std::forward(func), subject ) ) + Observer::ObserverBase( CreateEventObserverNode(std::forward(func), subject) ) { } - // Constructed synced event observer + // Construct event observer with explicit group + template + Observer(const ReactiveGroupBase& group, F&& func, const EventBase& subject) : + Observer::ObserverBase( CreateEventObserverNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), std::forward(func), subject) ) + { } + + // Constructed synced event observer with implicit group template Observer(F&& func, const EventBase& subject, const SignalBase& ... signals) : Observer::ObserverBase( CreateSyncedEventObserverNode(std::forward(func), subject, signals ...) ) { } + + // Constructed synced event observer with explicit group + template + Observer(const ReactiveGroupBase& group, F&& func, const EventBase& subject, const SignalBase& ... signals) : + Observer::ObserverBase( CreateSyncedEventObserverNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), std::forward(func), subject, signals ...) ) + { } }; template <> @@ -155,23 +186,41 @@ class Observer : public ObserverBase Observer& operator=(Observer&& other) { Observer::ObserverBase::operator=(std::move(other)); return *this; } - // Construct signal observer + // Construct signal observer with implicit group template Observer(F&& func, const SignalBase& ... subjects) : Observer::ObserverBase( CreateSignalObserverNode(std::forward(func), subjects ...) ) { } - // Construct event observer + // Construct signal observer with explicit group + template + Observer(const ReactiveGroupBase& group, F&& func, const SignalBase& ... subjects) : + Observer::ObserverBase( CreateSignalObserverNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), std::forward(func), subjects ...) ) + { } + + // Construct event observer with implicit group template Observer(F&& func, const EventBase& subject) : - Observer::ObserverBase( CreateEventObserverNode(std::forward(func), subject ) ) + Observer::ObserverBase( CreateEventObserverNode(std::forward(func), subject) ) { } - // Constructed synced event observer + // Construct event observer with explicit group + template + Observer(const ReactiveGroupBase& group, F&& func, const EventBase& subject) : + Observer::ObserverBase( CreateEventObserverNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), std::forward(func), subject) ) + { } + + // Constructed synced event observer with implicit group template Observer(F&& func, const EventBase& subject, const SignalBase& ... signals) : Observer::ObserverBase( CreateSyncedEventObserverNode(std::forward(func), subject, signals ...) ) { } + + // Constructed synced event observer with explicit group + template + Observer(const ReactiveGroupBase& group, F&& func, const EventBase& subject, const SignalBase& ... signals) : + Observer::ObserverBase( CreateSyncedEventObserverNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), std::forward(func), subject, signals ...) ) + { } }; /******************************************/ REACT_END /******************************************/ diff --git a/include/react/Signal.h b/include/react/Signal.h index dab00344..4f733f47 100644 --- a/include/react/Signal.h +++ b/include/react/Signal.h @@ -24,6 +24,12 @@ #include "react/detail/graph/SignalNodes.h" +/***************************************/ REACT_IMPL_BEGIN /**************************************/ + +struct PrivateSignalLinkNodeInterface; + +/****************************************/ REACT_IMPL_END /***************************************/ + /*****************************************/ REACT_BEGIN /*****************************************/ /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -37,7 +43,7 @@ class SignalBase public: // Private node ctor - SignalBase(REACT_IMPL::NodeCtorTag, std::shared_ptr&& nodePtr) : + SignalBase(REACT_IMPL::CtorTag, std::shared_ptr&& nodePtr) : nodePtr_( std::move(nodePtr) ) { } @@ -60,16 +66,22 @@ class SignalBase { return nodePtr_; } template - auto CreateFuncNode(F&& func, const SignalBase& dep1, const SignalBase& ... deps) -> decltype(auto) + auto CreateFuncNode(const std::shared_ptr& graphPtr, F&& func, const SignalBase& dep1, const SignalBase& ... deps) -> decltype(auto) { - using REACT_IMPL::GetCheckedGraphPtr; - using REACT_IMPL::PrivateNodeInterface; + using REACT_IMPL::PrivateSignalLinkNodeInterface; using FuncNodeType = REACT_IMPL::SignalFuncNode::type, T1, Ts ...>; return std::make_shared( - GetCheckedGraphPtr(dep1, deps ...), + graphPtr, std::forward(func), - PrivateNodeInterface::NodePtr(dep1), PrivateNodeInterface::NodePtr(deps) ...); + PrivateSignalLinkNodeInterface::GetLocalSignalNodePtr(graphPtr, dep1), PrivateSignalLinkNodeInterface::GetLocalSignalNodePtr(graphPtr, deps) ...); + } + + template + auto CreateFuncNode(F&& func, const SignalBase& dep1, const SignalBase& ... deps) -> decltype(auto) + { + using REACT_IMPL::PrivateNodeInterface; + return CreateFuncNode(PrivateNodeInterface::GraphPtr(dep1), std::forward(func), dep1, deps ...); } private: @@ -78,6 +90,7 @@ class SignalBase friend struct REACT_IMPL::PrivateNodeInterface; }; + /////////////////////////////////////////////////////////////////////////////////////////////////// /// VarSignalBase /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -112,21 +125,17 @@ class VarSignalBase : public SignalBase VarSignalBase(VarSignalBase&&) = default; VarSignalBase& operator=(VarSignalBase&&) = default; - auto CreateVarNode(const ReactiveGroupBase& group) -> decltype(auto) + static auto CreateVarNode(const std::shared_ptr& graphPtr) -> decltype(auto) { - using REACT_IMPL::PrivateReactiveGroupInterface; using VarNodeType = REACT_IMPL::VarSignalNode; - - return std::make_shared(PrivateReactiveGroupInterface::GraphPtr(group)); + return std::make_shared(graphPtr); } template - auto CreateVarNode(T&& value, const ReactiveGroupBase& group) -> decltype(auto) + static auto CreateVarNode(const std::shared_ptr& graphPtr, T&& value) -> decltype(auto) { - using REACT_IMPL::PrivateReactiveGroupInterface; using VarNodeType = REACT_IMPL::VarSignalNode; - - return std::make_shared(PrivateReactiveGroupInterface::GraphPtr(group), std::forward(value)); + return std::make_shared(graphPtr, std::forward(value)); } private: @@ -183,13 +192,12 @@ class SignalSlotBase : public SignalBase SignalSlotBase(SignalSlotBase&&) = default; SignalSlotBase& operator=(SignalSlotBase&&) = default; - auto CreateSlotNode(const SignalBase& input, const ReactiveGroupBase& group) -> decltype(auto) + static auto CreateSlotNode(const std::shared_ptr& graphPtr, const SignalBase& input) -> decltype(auto) { using REACT_IMPL::PrivateNodeInterface; - using REACT_IMPL::PrivateReactiveGroupInterface; using SlotNodeType = REACT_IMPL::SignalSlotNode; - return std::make_shared(PrivateReactiveGroupInterface::GraphPtr(group), PrivateNodeInterface::NodePtr(input)); + return std::make_shared(graphPtr, PrivateNodeInterface::NodePtr(input)); } private: @@ -197,7 +205,6 @@ class SignalSlotBase : public SignalBase { using REACT_IMPL::PrivateNodeInterface; using REACT_IMPL::NodeId; - using REACT_IMPL::ReactiveGraph; using SlotNodeType = REACT_IMPL::SignalSlotNode; SlotNodeType* castedPtr = static_cast(this->NodePtr().get()); @@ -208,6 +215,38 @@ class SignalSlotBase : public SignalBase } }; +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// SignalLinkBase +/////////////////////////////////////////////////////////////////////////////////////////////////// +template +class SignalLinkBase : public SignalBase +{ +public: + using SignalBase::SignalBase; + +protected: + SignalLinkBase() = default; + + SignalLinkBase(const SignalLinkBase&) = default; + SignalLinkBase& operator=(const SignalLinkBase&) = default; + + SignalLinkBase(SignalLinkBase&&) = default; + SignalLinkBase& operator=(SignalLinkBase&&) = default; + + static auto CreateLinkNode(const std::shared_ptr& graphPtr, const SignalBase& input) -> decltype(auto) + { + using REACT_IMPL::PrivateNodeInterface; + using REACT_IMPL::PrivateReactiveGroupInterface; + using LinkNodeType = REACT_IMPL::SignalLinkNode; + + auto node = std::make_shared(graphPtr, PrivateNodeInterface::GraphPtr(input), PrivateNodeInterface::NodePtr(input)); + node->SetWeakSelfPtr(std::weak_ptr{ node }); + return node; + } + + friend struct REACT_IMPL::PrivateSignalLinkNodeInterface; +}; + /////////////////////////////////////////////////////////////////////////////////////////////////// /// Signal /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -227,10 +266,16 @@ class Signal : public SignalBase Signal(Signal&&) = default; Signal& operator=(Signal&&) = default; - // Construct func signal + // Construct func signal with explicit group + template + explicit Signal(const ReactiveGroupBase& group, F&& func, const SignalBase& ... deps) : + Signal::SignalBase( REACT_IMPL::CtorTag{ }, CreateFuncNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), std::forward(func), deps ...) ) + { } + + // Construct func signal with implicit group template explicit Signal(F&& func, const SignalBase& ... deps) : - Signal::SignalBase( REACT_IMPL::NodeCtorTag{ }, CreateFuncNode(std::forward(func), deps ...) ) + Signal::SignalBase( REACT_IMPL::CtorTag{ }, CreateFuncNode(std::forward(func), deps ...) ) { } }; @@ -250,12 +295,6 @@ class Signal : public SignalBase Signal(Signal&&) = default; Signal& operator=(Signal&&) = default; - // Construct func signal - template - explicit Signal(F&& func, const SignalBase& ... deps) : - Signal::SignalBase( REACT_IMPL::NodeCtorTag{ }, CreateFuncNode(std::forward(func), deps ...) ) - { } - // Construct from unique Signal(Signal&& other) : Signal::SignalBase( std::move(other) ) @@ -264,6 +303,18 @@ class Signal : public SignalBase // Assign from unique Signal& operator=(Signal&& other) { Signal::SignalBase::operator=(std::move(other)); return *this; } + + // Construct func signal with explicit group + template + explicit Signal(const ReactiveGroupBase& group, F&& func, const SignalBase& ... deps) : + Signal::SignalBase( REACT_IMPL::CtorTag{ }, CreateFuncNode(std::forward(func), deps ...) ) + { } + + // Construct func signal with implicit group + template + explicit Signal(F&& func, const SignalBase& ... deps) : + Signal::SignalBase( REACT_IMPL::CtorTag{ }, CreateFuncNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), std::forward(func), deps ...) ) + { } }; /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -285,16 +336,15 @@ class VarSignal : public VarSignalBase VarSignal(VarSignal&&) = default; VarSignal& operator=(VarSignal&&) = default; - // Construct with default - template - explicit VarSignal(const TGroup& group) : - VarSignal::VarSignalBase( REACT_IMPL::NodeCtorTag{ }, CreateVarNode( group) ) + // Construct with group + default + explicit VarSignal(const ReactiveGroupBase& group) : + VarSignal::VarSignalBase( REACT_IMPL::CtorTag{ }, CreateVarNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group)) ) { } - // Construct with value - template - VarSignal(T&& value, const TGroup& group) : - VarSignal::VarSignalBase( REACT_IMPL::NodeCtorTag{ }, CreateVarNode(std::forward(value), group) ) + // Construct with group + value + template + VarSignal(const ReactiveGroupBase& group, T&& value) : + VarSignal::VarSignalBase( REACT_IMPL::CtorTag{ }, CreateVarNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), std::forward(value)) ) { } }; @@ -324,15 +374,14 @@ class VarSignal : public VarSignalBase { VarSignal::VarSignalBase::operator=(std::move(other)); return *this; } // Construct with default - template - explicit VarSignal(const TGroup& group) : - VarSignal::VarSignalBase( REACT_IMPL::NodeCtorTag{ }, CreateVarNode( group) ) + explicit VarSignal(const ReactiveGroupBase& group) : + VarSignal::VarSignalBase( REACT_IMPL::CtorTag{ }, CreateVarNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group)) ) { } // Construct with value - template - VarSignal(T&& value, const TGroup& group) : - VarSignal::VarSignalBase( REACT_IMPL::NodeCtorTag{ }, CreateVarNode(std::forward(value), group) ) + template + VarSignal(const ReactiveGroupBase& group, T&& value) : + VarSignal::VarSignalBase( REACT_IMPL::CtorTag{ }, CreateVarNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), std::forward(value)) ) { } }; @@ -355,14 +404,19 @@ class SignalSlot : public SignalSlotBase SignalSlot(SignalSlot&&) = default; SignalSlot& operator=(SignalSlot&&) = default; - // Construct with default + // Construct with group + default explicit SignalSlot(const ReactiveGroupBase& group) : - SignalSlot::SignalSlotBase( REACT_IMPL::NodeCtorTag{ }, CreateSlotNode( group) ) + SignalSlot::SignalSlotBase( REACT_IMPL::CtorTag{ }, CreateSlotNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group)) ) { } - // Construct with value - SignalSlot(const SignalBase& input, const ReactiveGroupBase& group) : - SignalSlot::SignalSlotBase( REACT_IMPL::NodeCtorTag{ }, CreateSlotNode(input, group) ) + // Construct with group + value + SignalSlot(const ReactiveGroupBase& group, const SignalBase& input) : + SignalSlot::SignalSlotBase( REACT_IMPL::CtorTag{ }, CreateSlotNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), input) ) + { } + + // Construct with value + explicit SignalSlot(const SignalBase& input) : + SignalSlot::SignalSlotBase( REACT_IMPL::CtorTag{ }, CreateSlotNode(REACT_IMPL::PrivateNodeInterface::GraphPtr(input), input) ) { } }; @@ -391,14 +445,90 @@ class SignalSlot : public SignalSlotBase SignalSlot& operator=(SignalSlot&& other) { SignalSlot::SignalSlotBase::operator=(std::move(other)); return *this; } - // Construct with default + // Construct with group + default explicit SignalSlot(const ReactiveGroupBase& group) : - SignalSlot::SignalSlotBase( REACT_IMPL::NodeCtorTag{ }, CreateSlotNode( group) ) + SignalSlot::SignalSlotBase( REACT_IMPL::CtorTag{ }, CreateSlotNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group)) ) + { } + + // Construct with group + value + SignalSlot(const ReactiveGroupBase& group, const SignalBase& input) : + SignalSlot::SignalSlotBase( REACT_IMPL::CtorTag{ }, CreateSlotNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), input) ) + { } + + // Construct with value + explicit SignalSlot(const SignalBase& input) : + SignalSlot::SignalSlotBase( REACT_IMPL::CtorTag{ }, CreateSlotNode(REACT_IMPL::PrivateNodeInterface::GraphPtr(input), input) ) + { } +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// SignalLink +/////////////////////////////////////////////////////////////////////////////////////////////////// +template +class SignalLink : public SignalLinkBase +{ +public: + using SignalLinkBase::SignalLinkBase; + + using ValueType = S; + + SignalLink() = delete; + + SignalLink(const SignalLink&) = delete; + SignalLink& operator=(const SignalLink&) = delete; + + SignalLink(SignalLink&&) = default; + SignalLink& operator=(SignalLink&&) = default; + + // Construct with default + explicit SignalLink(const ReactiveGroupBase& group) : + SignalLink::SignalLinkBase( REACT_IMPL::CtorTag{ }, CreateLinkNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group)) ) + { } + + // Construct with group + value + SignalLink(const ReactiveGroupBase& group, const SignalBase& input) : + SignalLink::SignalLinkBase( REACT_IMPL::CtorTag{ }, CreateLinkNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), input) ) + { } + + // Construct with value + explicit SignalLink(const SignalBase& input) : + SignalLink::SignalLinkBase( REACT_IMPL::CtorTag{ }, CreateLinkNode(REACT_IMPL::PrivateNodeInterface::GraphPtr(input), input) ) + { } +}; + +template +class SignalLink : public SignalLinkBase +{ +public: + using SignalLinkBase::SignalLinkBase; + + using ValueType = S; + + SignalLink() = delete; + + SignalLink(const SignalLink&) = default; + SignalLink& operator=(const SignalLink&) = default; + + SignalLink(SignalLink&&) = default; + SignalLink& operator=(SignalLink&&) = default; + + // Construct from unique + SignalLink(SignalLink&& other) : + SignalLink::SignalLinkBase( std::move(other) ) + { } + + // Assign from unique + SignalLink& operator=(SignalSlot&& other) + { SignalLink::SignalLinkBase::operator=(std::move(other)); return *this; } + + // Construct with default + explicit SignalLink(const ReactiveGroupBase& group) : + SignalLink::SignalLinkBase( REACT_IMPL::CtorTag{ }, CreateLinkNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group)) ) { } // Construct with value - SignalSlot(const SignalBase& input, const ReactiveGroupBase& group) : - SignalSlot::SignalSlotBase( REACT_IMPL::NodeCtorTag{ }, CreateSlotNode(input, group) ) + SignalLink(const ReactiveGroupBase& group, const SignalBase& input) : + SignalLink::SignalLinkBase( REACT_IMPL::CtorTag{ }, CreateLinkNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), input) ) { } }; @@ -412,6 +542,24 @@ bool Equals(const SignalBase& lhs, const SignalBase& rhs) return lhs.Equals(rhs); } +struct PrivateSignalLinkNodeInterface +{ + template + static auto GetLocalSignalNodePtr(const std::shared_ptr& targetGraph, const SignalBase& sig) -> std::shared_ptr> + { + const std::shared_ptr& sourceGraph = PrivateNodeInterface::GraphPtr(sig); + + if (sourceGraph == targetGraph) + { + return PrivateNodeInterface::NodePtr(sig); + } + else + { + return SignalLinkBase::CreateLinkNode(targetGraph, sig); + } + } +}; + /****************************************/ REACT_IMPL_END /***************************************/ /////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/include/react/detail/IReactiveGraph.h b/include/react/detail/IReactiveGraph.h index 594f3801..2ac8f291 100644 --- a/include/react/detail/IReactiveGraph.h +++ b/include/react/detail/IReactiveGraph.h @@ -13,7 +13,7 @@ #include #include -#include +#include #include #include "react/API.h" @@ -45,7 +45,7 @@ enum class NodeCategory input, dyninput, output, - link + linkoutput }; class ReactiveGraph; @@ -64,11 +64,11 @@ struct IReactiveNode virtual int GetDependencyCount() const = 0; }; -using LinkOutputList = std::vector>; +using LinkOutputMap = std::unordered_map>>; struct ILinkOutputNode : public IReactiveNode { - virtual void CollectOutput(LinkOutputList& output) = 0; + virtual void CollectOutput(LinkOutputMap& output) = 0; }; /****************************************/ REACT_IMPL_END /***************************************/ diff --git a/include/react/detail/graph/EventNodes.h b/include/react/detail/graph/EventNodes.h index 6a457a98..f188e55c 100644 --- a/include/react/detail/graph/EventNodes.h +++ b/include/react/detail/graph/EventNodes.h @@ -469,7 +469,8 @@ class EventJoinNode : public EventStreamNode> // All slots ready? apply( - [this, &isReady] (Slot& ... slots) { + [this, &isReady] (Slot& ... slots) + { // Todo: combine return values instead REACT_EXPAND_PACK(CheckSlot(slots, isReady)); }, @@ -534,6 +535,104 @@ class EventJoinNode : public EventStreamNode> std::tuple...> slots_; }; +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// EventLinkNode +/////////////////////////////////////////////////////////////////////////////////////////////////// +template +class EventLinkNode : public EventStreamNode +{ +public: + EventLinkNode(const std::shared_ptr& graphPtr, const std::shared_ptr& srcGraphPtr, const std::shared_ptr>& dep) : + EventLinkNode::EventStreamNode( graphPtr ), + linkOutput_( srcGraphPtr, dep ) + { + this->RegisterMe(NodeCategory::input); + } + + ~EventLinkNode() + { + this->UnregisterMe(); + } + + void SetWeakSelfPtr(const std::weak_ptr& self) + { linkOutput_.parent = self; } + + virtual const char* GetNodeType() const override + { return "EventLink"; } + + virtual int GetDependencyCount() const override + { return 1; } + + virtual UpdateResult Update(TurnId turnId, int successorCount) override + { + this->SetPendingSuccessorCount(successorCount); + return UpdateResult::changed; + } + + void SetEvents(EventLinkNode::EventStreamNode::StorageType&& events) + { this->Events() = std::move(events); } + +private: + struct VirtualOutputNode : public ILinkOutputNode + { + VirtualOutputNode(const std::shared_ptr& srcGraphPtrIn, const std::shared_ptr>& depIn) : + parent( ), + srcGraphPtr( srcGraphPtrIn ), + dep( depIn ) + { + nodeId = srcGraphPtr->RegisterNode(this, NodeCategory::linkoutput); + srcGraphPtr->OnNodeAttach(nodeId, dep->GetNodeId()); + } + + ~VirtualOutputNode() + { + srcGraphPtr->OnNodeDetach(nodeId, dep->GetNodeId()); + srcGraphPtr->UnregisterNode(nodeId); + } + + virtual const char* GetNodeType() const override + { return "EventLinkOutput"; } + + virtual int GetDependencyCount() const override + { return 1; } + + virtual UpdateResult Update(TurnId turnId, int successorCount) override + { + return UpdateResult::changed; + } + + virtual void CollectOutput(LinkOutputMap& output) override + { + if (auto p = parent.lock()) + { + auto* rawPtr = p->GraphPtr().get(); + output[rawPtr].push_back( + [storedParent = std::move(p), storedEvents = dep->Events()] () mutable + { + NodeId nodeId = storedParent->GetNodeId(); + auto& graphPtr = storedParent->GraphPtr(); + + graphPtr->AddInput(nodeId, + [&storedParent, &storedEvents] + { + storedParent->SetEvents(std::move(storedEvents)); + }); + }); + } + } + + std::weak_ptr parent; + + NodeId nodeId; + + std::shared_ptr> dep; + + std::shared_ptr srcGraphPtr; + }; + + VirtualOutputNode linkOutput_; +}; + /****************************************/ REACT_IMPL_END /***************************************/ #endif // REACT_DETAIL_GRAPH_EVENTNODES_H_INCLUDED \ No newline at end of file diff --git a/include/react/detail/graph/PropagationST.h b/include/react/detail/graph/PropagationST.h index e0eb2f59..182cfcd0 100644 --- a/include/react/detail/graph/PropagationST.h +++ b/include/react/detail/graph/PropagationST.h @@ -44,6 +44,8 @@ class TransactionQueue template void Push(TransactionFlags flags, F&& transaction) { + transactions_.push(StoredTransaction{ flags, std::forward(transaction) }); + if (count_.fetch_add(1, std::memory_order_relaxed) == 0) tbb::task::enqueue(*new(tbb::task::allocate_root()) WorkerTask(*this)); } @@ -95,9 +97,6 @@ class ReactiveGraph void OnDynamicNodeAttach(NodeId node, NodeId parentId, TurnId turnId); void OnDynamicNodeDetach(NodeId node, NodeId parentId, TurnId turnId); - LinkId AddGroupLink(ILinkNodeOutput* nodePtr, NodeCategory category); - void RemoveGroupLink(LinkId nodeId); - template void AddInput(NodeId nodeId, F&& inputCallback); @@ -118,7 +117,7 @@ class ReactiveGraph NodeData(IReactiveNode* nodePtrIn, NodeCategory categoryIn) : nodePtr( nodePtrIn ), category(categoryIn) - { } + { } NodeCategory category = NodeCategory::normal; @@ -127,7 +126,6 @@ class ReactiveGraph bool queued = false; IReactiveNode* nodePtr = nullptr; - std::vector successors; }; @@ -167,7 +165,7 @@ class ReactiveGraph TopoQueue scheduledNodes_; IndexMap nodeData_; std::vector changedInputs_; - std::vector scheduledLinkNodes_; + LinkOutputMap scheduledLinkOutputs_; bool isTransactionActive_ = false; }; @@ -239,6 +237,9 @@ void ReactiveGraph::AddInput(NodeId nodeId, F&& inputCallback) if (! scheduledNodes_.IsEmpty()) Propagate(); + + if (! scheduledLinkOutputs_.empty()) + UpdateLinkNodes(); } } } @@ -274,7 +275,7 @@ void ReactiveGraph::DoTransaction(F&& transactionCallback) if (! scheduledNodes_.IsEmpty()) Propagate(); - if (!scheduledLinkNodes_.empty()) + if (! scheduledLinkOutputs_.empty()) UpdateLinkNodes(); } @@ -302,6 +303,13 @@ void ReactiveGraph::Propagate() continue; } + // Special handling for link output nodes. They have no successors and they don't have to be updated. + if (node.category == NodeCategory::linkoutput) + { + static_cast(node.nodePtr)->CollectOutput(scheduledLinkOutputs_); + continue; + } + int successorCount = node.successors.size(); if (nodePtr->Update(0, successorCount) == UpdateResult::changed) @@ -316,10 +324,35 @@ void ReactiveGraph::Propagate() void ReactiveGraph::UpdateLinkNodes() { - for (const auto& x : scheduledLinkNodes_) - { - - } + for (auto& e : scheduledLinkOutputs_) + { + e.first->EnqueueTransaction(TransactionFlags::none, + [inputs = std::move(e.second)] + { + for (auto& callback : inputs) + callback(); + }); + } + + scheduledLinkOutputs_.clear(); + + /*using ElementType = std::pair; + + auto from = scheduledLinkOutputs_.begin(); + auto to = scheduledLinkOutputs_.end(); + + for (auto it = from; it != to; ++it) + { + ReactiveGraph* graphPtr = it->first; + auto p = std::partition(it, to, [=] (ReactiveGraph* e) { return e == graphPtr }); + + for (auto it2 = p; it2 != to; ++it2) + { + graphPtr->EnqueueLinkTransaction(); + } + } + + scheduledLinkOutputs_.clear();*/ } void ReactiveGraph::ScheduleSuccessors(NodeData& node) @@ -331,11 +364,7 @@ void ReactiveGraph::ScheduleSuccessors(NodeData& node) if (!succ.queued) { succ.queued = true; - - if (node.category != NodeCategory::link) - scheduledNodes_.Push(succId, succ.level); - else - scheduledLinkNodes_.push_back(succId); + scheduledNodes_.Push(succId, succ.level); } } } @@ -400,7 +429,7 @@ size_t TransactionQueue::ProcessNextBatch() { if (!skipPop) { - if (transactions_.try_pop(curTransaction)) + if (!transactions_.try_pop(curTransaction)) return popCount; canMerge = IsBitmaskSet(curTransaction.flags, TransactionFlags::allow_merging); diff --git a/include/react/detail/graph/SignalNodes.h b/include/react/detail/graph/SignalNodes.h index 2bdd3eac..d084945d 100644 --- a/include/react/detail/graph/SignalNodes.h +++ b/include/react/detail/graph/SignalNodes.h @@ -267,7 +267,7 @@ class SignalSlotNode : public SignalNode { } virtual const char* GetNodeType() const override - { return "SignalSlotVirtualInput"; } + { return "SignalSlotInput"; } virtual int GetDependencyCount() const override { return 0; } @@ -301,7 +301,7 @@ class SignalSlotNode : public SignalNode }; /////////////////////////////////////////////////////////////////////////////////////////////////// -/// SignalBridgeNode +/// SignalLinkNode /////////////////////////////////////////////////////////////////////////////////////////////////// template class SignalLinkNode : public SignalNode @@ -309,85 +309,95 @@ class SignalLinkNode : public SignalNode public: SignalLinkNode(const std::shared_ptr& graphPtr, const std::shared_ptr& srcGraphPtr, const std::shared_ptr>& dep) : SignalLinkNode::SignalNode( graphPtr, dep->Value() ), - linkOutput_( *this, srcGraphPtr, dep ) + linkOutput_( srcGraphPtr, dep ) { - slotInput_.nodeId = GraphPtr()->RegisterNode(&linkOutput_, NodeCategory::dyninput); - this->RegisterMe(); - - this->AttachToMe(slotInput_.nodeId); - this->AttachToMe(dep->GetNodeId()); + this->RegisterMe(NodeCategory::input); } ~SignalLinkNode() { - this->DetachFromMe(slotInput_.dep->GetNodeId()); - this->DetachFromMe(slotInput_.nodeId); - this->UnregisterMe(); - GraphPtr()->UnregisterNode(slotInput_.nodeId); } + void SetWeakSelfPtr(const std::weak_ptr& self) + { linkOutput_.parent = self; } + virtual const char* GetNodeType() const override { return "SignalLink"; } virtual int GetDependencyCount() const override - { return 2; } + { return 1; } virtual UpdateResult Update(TurnId turnId, int successorCount) override { - {// outputDataMutex - std::lock_guard lock(linkOutput_.outputDataMutex); - this->Value() = std::move(linkOutput_.outputData.front()); - linkOutput_.outputData.pop(); - }// ~outputDataMutex - return UpdateResult::changed; } + template + void SetValue(T&& newValue) + { + this->Value() = std::forward(newValue); + } + private: struct VirtualOutputNode : public ILinkOutputNode { - VirtualOutputNode(SignalSlotNode& parentIn, const std::shared_ptr& srcGraphPtrIn, const std::shared_ptr>& depIn) : - parent( parentIn ), - srcGraphPtr(srcGraphPtrIn), + VirtualOutputNode(const std::shared_ptr& srcGraphPtrIn, const std::shared_ptr>& depIn) : + parent( ), + srcGraphPtr( srcGraphPtrIn ), dep( depIn ) - { } + { + nodeId = srcGraphPtr->RegisterNode(this, NodeCategory::linkoutput); + srcGraphPtr->OnNodeAttach(nodeId, dep->GetNodeId()); + } + + ~VirtualOutputNode() + { + srcGraphPtr->OnNodeDetach(nodeId, dep->GetNodeId()); + srcGraphPtr->UnregisterNode(nodeId); + } virtual const char* GetNodeType() const override - { return "SignalLinkVirtualOutput"; } + { return "SignalLinkOutput"; } virtual int GetDependencyCount() const override { return 1; } virtual UpdateResult Update(TurnId turnId, int successorCount) override - { - {// outputDataMutex - std::lock_guard lock(outputDataMutex); - outputData.push(dep->Value()); - }// ~outputDataMutex - + { return UpdateResult::changed; } - virtual void CollectOutput(LinkOutputList& output) override - { output.emplace_back(srcGraphPtr.get(), &parent); } - - SignalSlotNode& parent; + virtual void CollectOutput(LinkOutputMap& output) override + { + if (auto p = parent.lock()) + { + auto* rawPtr = p->GraphPtr().get(); + output[rawPtr].push_back( + [storedParent = std::move(p), storedValue = dep->Value()] + { + NodeId nodeId = storedParent->GetNodeId(); + auto& graphPtr = storedParent->GraphPtr(); + + graphPtr->AddInput(nodeId, + [&storedParent, &storedValue] + { + storedParent->SetValue(std::move(storedValue)); + }); + }); + } + } + + std::weak_ptr parent; NodeId nodeId; std::shared_ptr> dep; - std::mutex outputDataMutex; - - std::queue> outputData; - std::shared_ptr srcGraphPtr; }; VirtualOutputNode linkOutput_; - - }; /****************************************/ REACT_IMPL_END /***************************************/ From 96302158e61ec39130db3082b048756417714a98 Mon Sep 17 00:00:00 2001 From: schlangster Date: Sun, 11 Dec 2016 23:16:34 +0100 Subject: [PATCH 37/75] group progress --- examples/src/Main.cpp | 28 ++-- include/react/API.h | 6 - include/react/Algorithm.h | 178 ++++++++++++++++++--- include/react/Event.h | 50 +++--- include/react/Group.h | 1 - include/react/Observer.h | 27 ++-- include/react/Signal.h | 52 +++--- include/react/detail/ReactiveInput.h | 7 +- include/react/detail/graph/EventNodes.h | 72 ++++----- include/react/detail/graph/ObserverNodes.h | 2 +- include/react/detail/graph/SignalNodes.h | 60 +++---- 11 files changed, 304 insertions(+), 179 deletions(-) diff --git a/examples/src/Main.cpp b/examples/src/Main.cpp index 62d5c079..e4fe6f5d 100644 --- a/examples/src/Main.cpp +++ b/examples/src/Main.cpp @@ -45,12 +45,20 @@ template void PrintEvents(EventRange evts) printf(" Event: %d\n", e); } +template void PrintSyncedEvents(EventRange evts, int a, int b) +{ + printf("Processing events...\n"); + + for (const auto& e : evts) + printf(" Event: %d, %d, %d\n", e, a, b); +} + template bool FilterFunc(T v) { return v > 10; } -int main2() +int main() { ReactiveGroup<> group; @@ -60,7 +68,7 @@ int main2() VarSignal y{ group, 0 }; VarSignal z{ group, 0 }; - Signal area{ Multiply, x, y }; + Signal area{ group, Multiply, x, y }; Signal volume{ Multiply, area, z }; Observer<> areaObs{ PrintArea, area }; @@ -136,15 +144,21 @@ int main2() ReactiveGroup<> group1; ReactiveGroup<> group2; + VarSignal s1{ group1, 10 }; + VarSignal s2{ group2, 11 }; + EventSource e1{ group1 }; EventSource e2{ group2 }; + auto hold = Hold(group1, 0, e1); + auto merged = Merge(group2, e1, e2); auto joined = Join(e1, e2); auto joined2 = Join(group1, e1, e2); Observer<> eventObs{ PrintEvents, merged }; + Observer<> eventObs2{ group2, PrintSyncedEvents, merged, s1, s2 }; e1.Emit(222); @@ -154,16 +168,6 @@ int main2() return 0; } -int main() -{ - ReactiveGroup<> group; - - VarSignal a{ }; - VarSignal b{ }; - -} - - diff --git a/include/react/API.h b/include/react/API.h index 79a44241..b1e86ad1 100644 --- a/include/react/API.h +++ b/include/react/API.h @@ -23,12 +23,6 @@ enum OwnershipPolicy shared }; -enum ReferencePolicy -{ - strong, - weak -}; - enum class WeightHint { automatic, diff --git a/include/react/Algorithm.h b/include/react/Algorithm.h index af6bce46..9a033559 100644 --- a/include/react/Algorithm.h +++ b/include/react/Algorithm.h @@ -18,47 +18,107 @@ #include "react/API.h" #include "react/detail/graph/AlgorithmNodes.h" +#include "Event.h" +#include "Signal.h" + /*****************************************/ REACT_BEGIN /*****************************************/ /////////////////////////////////////////////////////////////////////////////////////////////////// /// Hold - Hold the most recent event in a signal /////////////////////////////////////////////////////////////////////////////////////////////////// template -auto Hold(T&& initialValue, const EventBase& events) -> Signal +auto Hold(const ReactiveGroupBase& group, T&& initialValue, const EventBase& evnt) -> Signal { using REACT_IMPL::HoldNode; + using REACT_IMPL::PrivateEventLinkNodeInterface; + using REACT_IMPL::PrivateReactiveGroupInterface; + using REACT_IMPL::CtorTag; + + const auto& graphPtr = PrivateReactiveGroupInterface::GraphPtr(group); + + return Signal( CtorTag{ }, std::make_shared>( + graphPtr, std::forward(initialValue), PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, evnt)) ); +} + +template +auto Hold(T&& initialValue, const EventBase& evnt) -> Signal +{ + using REACT_IMPL::HoldNode; + using REACT_IMPL::PrivateEventLinkNodeInterface; using REACT_IMPL::PrivateNodeInterface; - using REACT_IMPL::NodeCtorTag; + using REACT_IMPL::CtorTag; + + const auto& graphPtr = PrivateNodeInterface::GraphPtr(evnt); - return Signal( NodeCtorTag{ }, std::make_shared>( - PrivateNodeInterface::GraphPtr(events), std::forward(initialValue), PrivateNodeInterface::NodePtr(events)) ); + return Signal( CtorTag{ }, std::make_shared>( + graphPtr, std::forward(initialValue), PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, evnt)) ); } /////////////////////////////////////////////////////////////////////////////////////////////////// /// Monitor - Emits value changes of target signal /////////////////////////////////////////////////////////////////////////////////////////////////// +template +auto Monitor(const ReactiveGroupBase& group, const SignalBase& signal) -> Event +{ + using REACT_IMPL::MonitorNode; + using REACT_IMPL::PrivateSignalLinkNodeInterface; + using REACT_IMPL::PrivateReactiveGroupInterface; + using REACT_IMPL::CtorTag; + + const auto& graphPtr = PrivateReactiveGroupInterface::GraphPtr(group); + + return Event( CtorTag{ }, std::make_shared>( + graphPtr, PrivateSignalLinkNodeInterface::GetLocalNodePtr(graphPtr, signal)) ); +} + template auto Monitor(const SignalBase& signal) -> Event { using REACT_IMPL::MonitorNode; + using REACT_IMPL::PrivateSignalLinkNodeInterface; using REACT_IMPL::PrivateNodeInterface; - using REACT_IMPL::NodeCtorTag; + using REACT_IMPL::CtorTag; + + const auto& graphPtr = PrivateNodeInterface::GraphPtr(evnt); - return Event( NodeCtorTag{ }, std::make_shared>( - PrivateNodeInterface::GraphPtr(signal), PrivateNodeInterface::NodePtr(signal)) ); + return Event( CtorTag{ }, std::make_shared>( + graphPtr, PrivateSignalLinkNodeInterface::GetLocalNodePtr(graphPtr, signal)) ); } /////////////////////////////////////////////////////////////////////////////////////////////////// /// Iterate - Iteratively combines signal value with values from event stream (aka Fold) /////////////////////////////////////////////////////////////////////////////////////////////////// template -auto Iterate(T&& init, F&& func, const EventBase& events) -> Signal +auto Iterate(const ReactiveGroupBase& group, T&& initialValue, F&& func, const EventBase& evnt) -> Signal { using REACT_IMPL::IterateNode; using REACT_IMPL::IterateByRefNode; using REACT_IMPL::IsCallableWith; + using REACT_IMPL::PrivateEventLinkNodeInterface; + using REACT_IMPL::PrivateReactiveGroupInterface; + using REACT_IMPL::CtorTag; + + using FuncType = typename std::decay::type; + using IterNodeType = typename std::conditional< + IsCallableWith,S>::value, + IterateNode, + IterateByRefNode>::type; + + const auto& graphPtr = PrivateReactiveGroupInterface::GraphPtr(group); + + return Signal( CtorTag{ }, std::make_shared( + graphPtr, std::forward(initialValue), std::forward(func), PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, evnt) )); +} + +template +auto Iterate(T&& initialValue, F&& func, const EventBase& evnt) -> Signal +{ + using REACT_IMPL::IterateNode; + using REACT_IMPL::IterateByRefNode; + using REACT_IMPL::IsCallableWith; + using REACT_IMPL::PrivateEventLinkNodeInterface; using REACT_IMPL::PrivateNodeInterface; - using REACT_IMPL::NodeCtorTag; + using REACT_IMPL::CtorTag; using FuncType = typename std::decay::type; using IterNodeType = typename std::conditional< @@ -66,22 +126,49 @@ auto Iterate(T&& init, F&& func, const EventBase& events) -> Signal, IterateByRefNode>::type; - return Signal( NodeCtorTag{ }, std::make_shared( - PrivateNodeInterface::GraphPtr(events), std::forward(init), std::forward(func), PrivateNodeInterface::NodePtr(events) )); + const auto& graphPtr = PrivateNodeInterface::GraphPtr(evnt); + + return Signal( CtorTag{ }, std::make_shared( + graphPtr, std::forward(initialValue), std::forward(func), PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, evnt) )); } /////////////////////////////////////////////////////////////////////////////////////////////////// /// Iterate - Synced /////////////////////////////////////////////////////////////////////////////////////////////////// template -auto Iterate(T&& init, F&& func, const EventBase& events, const SignalBase& ... signals) -> Signal +auto Iterate(const ReactiveGroupBase& group, T&& initialValue, F&& func, const EventBase& evnt, const SignalBase& ... signals) -> Signal { using REACT_IMPL::SyncedIterateNode; using REACT_IMPL::SyncedIterateByRefNode; using REACT_IMPL::IsCallableWith; - using REACT_IMPL::GetCheckedGraphPtr; + using REACT_IMPL::PrivateSignalLinkNodeInterface; + using REACT_IMPL::PrivateEventLinkNodeInterface; + using REACT_IMPL::PrivateReactiveGroupInterface; + using REACT_IMPL::CtorTag; + + using FuncType = typename std::decay::type; + using IterNodeType = typename std::conditional< + IsCallableWith, S, Us ...>::value, + SyncedIterateNode, + SyncedIterateByRefNode>::type; + + const auto& graphPtr = PrivateReactiveGroupInterface::GraphPtr(group); + + return Signal( CtorTag{ }, std::make_shared( + graphPtr, std::forward(initialValue), std::forward(func), + PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, evnt), PrivateSignalLinkNodeInterface::GetLocalNodePtr(graphPtr, signals) ...)); +} + +template +auto Iterate(T&& initialValue, F&& func, const EventBase& evnt, const SignalBase& ... signals) -> Signal +{ + using REACT_IMPL::SyncedIterateNode; + using REACT_IMPL::SyncedIterateByRefNode; + using REACT_IMPL::IsCallableWith; + using REACT_IMPL::PrivateSignalLinkNodeInterface; + using REACT_IMPL::PrivateEventLinkNodeInterface;; using REACT_IMPL::PrivateNodeInterface; - using REACT_IMPL::NodeCtorTag; + using REACT_IMPL::CtorTag; using FuncType = typename std::decay::type; using IterNodeType = typename std::conditional< @@ -89,38 +176,77 @@ auto Iterate(T&& init, F&& func, const EventBase& events, const SignalBase, SyncedIterateByRefNode>::type; - return Signal( NodeCtorTag{ }, std::make_shared( - GetCheckedGraphPtr(events, signals ...), - std::forward(init), std::forward(func), PrivateNodeInterface::NodePtr(events), PrivateNodeInterface::NodePtr(signals) ...)); + const auto& graphPtr = PrivateNodeInterface::GraphPtr(evnt); + + return Signal( CtorTag{ }, std::make_shared( + graphPtr, std::forward(initialValue), std::forward(func), + PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, evnt), PrivateSignalLinkNodeInterface::GetLocalNodePtr(graphPtr, signals) ...)); } /////////////////////////////////////////////////////////////////////////////////////////////////// /// Snapshot - Sets signal value to value of other signal when event is received /////////////////////////////////////////////////////////////////////////////////////////////////// template -auto Snapshot(const SignalBase& signal, const EventBase& trigger) -> Signal +auto Snapshot(const ReactiveGroupBase& group, const SignalBase& signal, const EventBase& evnt) -> Signal { using REACT_IMPL::SnapshotNode; - using REACT_IMPL::GetCheckedGraphPtr; + using REACT_IMPL::PrivateSignalLinkNodeInterface; + using REACT_IMPL::PrivateEventLinkNodeInterface;; + using REACT_IMPL::PrivateReactiveGroupInterface; + using REACT_IMPL::CtorTag; + + const auto& graphPtr = PrivateReactiveGroupInterface::GraphPtr(group); + + return Event( CtorTag{ }, std::make_shared>( + graphPtr, PrivateNodeInterface::NodePtr(signal), PrivateNodeInterface::NodePtr(evnt)) ); +} + +template +auto Snapshot(const SignalBase& signal, const EventBase& evnt) -> Signal +{ + using REACT_IMPL::SnapshotNode; + using REACT_IMPL::PrivateSignalLinkNodeInterface; + using REACT_IMPL::PrivateEventLinkNodeInterface;; using REACT_IMPL::PrivateNodeInterface; - using REACT_IMPL::NodeCtorTag; + using REACT_IMPL::CtorTag; + + const auto& graphPtr = PrivateNodeInterface::GraphPtr(signal); - return Events( NodeCtorTag{ }, std::make_shared>( - GetCheckedGraphPtr(signal, trigger), PrivateNodeInterface::NodePtr(signal), PrivateNodeInterface::NodePtr(trigger)) ); + return Event( CtorTag{ }, std::make_shared>( + graphPtr, PrivateSignalLinkNodeInterface::GetLocalNodePtr(graphPtr, signal), PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, evnt)) ); } /////////////////////////////////////////////////////////////////////////////////////////////////// /// Pulse - Emits value of target signal when event is received /////////////////////////////////////////////////////////////////////////////////////////////////// template -auto Pulse(const SignalBase& signal, const EventBase& trigger) -> Event +auto Pulse(const ReactiveGroupBase& group, const SignalBase& signal, const EventBase& evnt) -> Event { using REACT_IMPL::PulseNode; - using REACT_IMPL::GetCheckedGraphPtr; + using REACT_IMPL::PrivateSignalLinkNodeInterface; + using REACT_IMPL::PrivateEventLinkNodeInterface;; + using REACT_IMPL::PrivateReactiveGroupInterface; + using REACT_IMPL::CtorTag; + + const auto& graphPtr = PrivateReactiveGroupInterface::GraphPtr(group); + + return Event( CtorTag{ }, std::make_shared>( + graphPtr, PrivateSignalLinkNodeInterface::NodePtr(graphPtr, signal), PrivateEventLinkNodeInterface::NodePtr(graphPtr, evnt)) ); +} + +template +auto Pulse(const SignalBase& signal, const EventBase& evnt) -> Event +{ + using REACT_IMPL::PulseNode; + using REACT_IMPL::PrivateSignalLinkNodeInterface; + using REACT_IMPL::PrivateEventLinkNodeInterface;; using REACT_IMPL::PrivateNodeInterface; + using REACT_IMPL::CtorTag; + + const auto& graphPtr = PrivateNodeInterface::GraphPtr(signal); - return Event( NodeCtorTag{ }, std::make_shared>( - GetCheckedGraphPtr(signal, trigger), PrivateNodeInterface::NodePtr(signal), PrivateNodeInterface::NodePtr(trigger)) ); + return Event( CtorTag{ }, std::make_shared>( + graphPtr, PrivateSignalLinkNodeInterface::GetLocalNodePtr(graphPtr, signal), PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, evnt)) ); } /******************************************/ REACT_END /******************************************/ diff --git a/include/react/Event.h b/include/react/Event.h index 89bcc0c8..bf8c0a05 100644 --- a/include/react/Event.h +++ b/include/react/Event.h @@ -230,11 +230,11 @@ class EventLinkBase : public EventBase using EventNodeType = REACT_IMPL::EventLinkNode; auto node = std::make_shared(graphPtr, PrivateNodeInterface::GraphPtr(input), PrivateNodeInterface::NodePtr(input)); - node->SetWeakSelfPtr(std::weak_ptr{ node }); - return node; + node->SetWeakSelfPtr(std::weak_ptr{ node }); + return node; } - friend struct REACT_IMPL::PrivateEventLinkNodeInterface; + friend struct REACT_IMPL::PrivateEventLinkNodeInterface; }; /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -315,7 +315,7 @@ class Event : public EventBase Event::EventBase( REACT_IMPL::CtorTag{ }, CreateSyncedProcessingNode(std::forward(func), dep, signals ...) ) { } - template + template Event(const ReactiveGroupBase& group, F&& func, const EventBase& dep, const SignalBase& ... signals) : Event::EventBase( REACT_IMPL::CtorTag{ }, CreateSyncedProcessingNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), std::forward(func), dep, signals ...) ) { } @@ -452,10 +452,10 @@ auto Merge(const ReactiveGroupBase& group, const EventBase& dep1, const Even typename std::common_type::type, T>::type; - const auto& graphPtr = PrivateReactiveGroupInterface::GraphPtr(group); + const auto& graphPtr = PrivateReactiveGroupInterface::GraphPtr(group); return Event( CtorTag{ }, std::make_shared>( - graphPtr, PrivateEventLinkNodeInterface::GetLocalEventNodePtr(graphPtr, dep1), PrivateEventLinkNodeInterface::GetLocalEventNodePtr(graphPtr, deps) ...)); + graphPtr, PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, dep1), PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, deps) ...)); } template @@ -477,7 +477,7 @@ auto Merge(const EventBase& dep1, const EventBase& ... deps) -> decltype const auto& graphPtr = PrivateNodeInterface::GraphPtr(dep1); return Event( CtorTag{ }, std::make_shared>( - graphPtr, PrivateEventLinkNodeInterface::GetLocalEventNodePtr(graphPtr, dep1), PrivateEventLinkNodeInterface::GetLocalEventNodePtr(graphPtr, deps) ...)); + graphPtr, PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, dep1), PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, deps) ...)); } /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -591,7 +591,7 @@ auto Join(const ReactiveGroupBase& group, const EventBase& dep1, const Event { using REACT_IMPL::EventJoinNode; using REACT_IMPL::PrivateReactiveGroupInterface; - using REACT_IMPL::PrivateEventLinkNodeInterface; + using REACT_IMPL::PrivateEventLinkNodeInterface; using REACT_IMPL::CtorTag; static_assert(sizeof...(Us) > 0, "Join requires at least 2 inputs."); @@ -600,7 +600,7 @@ auto Join(const ReactiveGroupBase& group, const EventBase& dep1, const Event const auto& graphPtr = PrivateReactiveGroupInterface::GraphPtr(group); return Event, unique>( CtorTag{ }, std::make_shared>( - graphPtr, PrivateEventLinkNodeInterface::GetLocalEventNodePtr(graphPtr, dep1), PrivateEventLinkNodeInterface::GetLocalEventNodePtr(graphPtr, deps) ...)); + graphPtr, PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, dep1), PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, deps) ...)); } template @@ -608,7 +608,7 @@ auto Join(const EventBase& dep1, const EventBase& ... deps) -> Event 0, "Join requires at least 2 inputs."); @@ -617,7 +617,7 @@ auto Join(const EventBase& dep1, const EventBase& ... deps) -> Event, unique>( CtorTag{ }, std::make_shared>( - graphPtr, PrivateEventLinkNodeInterface::GetLocalEventNodePtr(graphPtr, dep1), PrivateEventLinkNodeInterface::GetLocalEventNodePtr(graphPtr, deps) ...)); + graphPtr, PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, dep1), PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, deps) ...)); } /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -649,20 +649,20 @@ bool Equals(const EventBase& lhs, const EventBase& rhs) struct PrivateEventLinkNodeInterface { - template - static auto GetLocalEventNodePtr(const std::shared_ptr& targetGraph, const EventBase& dep) -> std::shared_ptr> - { - const std::shared_ptr& sourceGraph = PrivateNodeInterface::GraphPtr(dep); - - if (sourceGraph == targetGraph) - { - return PrivateNodeInterface::NodePtr(dep); - } - else - { - return EventLinkBase::CreateLinkNode(targetGraph, dep); - } - } + template + static auto GetLocalNodePtr(const std::shared_ptr& targetGraph, const EventBase& dep) -> std::shared_ptr> + { + const std::shared_ptr& sourceGraph = PrivateNodeInterface::GraphPtr(dep); + + if (sourceGraph == targetGraph) + { + return PrivateNodeInterface::NodePtr(dep); + } + else + { + return EventLinkBase::CreateLinkNode(targetGraph, dep); + } + } }; /****************************************/ REACT_IMPL_END /***************************************/ diff --git a/include/react/Group.h b/include/react/Group.h index ac5c1b91..fc5e49f1 100644 --- a/include/react/Group.h +++ b/include/react/Group.h @@ -22,7 +22,6 @@ /***************************************/ REACT_IMPL_BEGIN /**************************************/ struct PrivateReactiveGroupInterface; -struct PrivateConcurrentReactiveGroupInterface; struct CtorTag { }; /****************************************/ REACT_IMPL_END /***************************************/ diff --git a/include/react/Observer.h b/include/react/Observer.h index 590c5baa..eea9ce5f 100644 --- a/include/react/Observer.h +++ b/include/react/Observer.h @@ -58,13 +58,13 @@ class ObserverBase template auto CreateSignalObserverNode(const std::shared_ptr& graphPtr, F&& func, const SignalBase& dep1, const SignalBase& ... deps) -> decltype(auto) { - using REACT_IMPL::PrivateSignalLinkNodeInterface; + using REACT_IMPL::PrivateSignalLinkNodeInterface; using ObsNodeType = REACT_IMPL::SignalObserverNode::type, T1, Ts ...>; return std::make_shared( graphPtr, std::forward(func), - PrivateSignalLinkNodeInterface::GetLocalSignalNodePtr(graphPtr, dep1), PrivateSignalLinkNodeInterface::GetLocalSignalNodePtr(graphPtr, deps) ...); + PrivateSignalLinkNodeInterface::GetLocalNodePtr(graphPtr, dep1), PrivateSignalLinkNodeInterface::GetLocalNodePtr(graphPtr, deps) ...); } template @@ -77,30 +77,35 @@ class ObserverBase template auto CreateEventObserverNode(const std::shared_ptr& graphPtr, F&& func, const EventBase& dep) -> decltype(auto) { - using REACT_IMPL::PrivateEventLinkNodeInterface; + using REACT_IMPL::PrivateEventLinkNodeInterface; using ObsNodeType = REACT_IMPL::EventObserverNode::type, T>; - return std::make_shared(graphPtr, std::forward(func), PrivateEventLinkNodeInterface::GetLocalEventNodePtr(graphPtr, dep)); + return std::make_shared(graphPtr, std::forward(func), PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, dep)); } template auto CreateEventObserverNode(F&& func, const EventBase& dep) -> decltype(auto) { using REACT_IMPL::PrivateNodeInterface; - return CreateSignalObserverNode(PrivateNodeInterface::GraphPtr(dep1), std::forward(func), dep1, deps ...); + return CreateEventObserverNode(PrivateNodeInterface::GraphPtr(dep), std::forward(func), dep); } template - auto CreateSyncedEventObserverNode(F&& func, const EventBase& dep, const SignalBase& ... syncs) -> decltype(auto) + auto CreateSyncedEventObserverNode(const std::shared_ptr& graphPtr, F&& func, const EventBase& dep, const SignalBase& ... syncs) -> decltype(auto) { - using REACT_IMPL::PrivateNodeInterface; - using REACT_IMPL::PrivateSignalLinkNodeInterface; + using REACT_IMPL::PrivateEventLinkNodeInterface; + using REACT_IMPL::PrivateSignalLinkNodeInterface; using ObsNodeType = REACT_IMPL::SyncedEventObserverNode::type, T, Us ...>; - const auto& graphPtr = PrivateNodeInterface::GraphPtr(dep); - return std::make_shared( - graphPtr, std::forward(func), PrivateSignalLinkNodeInterface::GetLocalSignalNodePtr(graphPtr, dep), PrivateSignalLinkNodeInterface::GetLocalSignalNodePtr(graphPtr, syncs) ...); + graphPtr, std::forward(func), PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, dep), PrivateSignalLinkNodeInterface::GetLocalNodePtr(graphPtr, syncs) ...); + } + + template + auto CreateSyncedEventObserverNode(F&& func, const EventBase& dep, const SignalBase& ... syncs) -> decltype(auto) + { + using REACT_IMPL::PrivateNodeInterface; + return CreateSyncedEventObserverNode(PrivateNodeInterface::GraphPtr(dep), std::forward(func), dep, syncs ...); } private: diff --git a/include/react/Signal.h b/include/react/Signal.h index 4f733f47..bd5f62df 100644 --- a/include/react/Signal.h +++ b/include/react/Signal.h @@ -68,20 +68,20 @@ class SignalBase template auto CreateFuncNode(const std::shared_ptr& graphPtr, F&& func, const SignalBase& dep1, const SignalBase& ... deps) -> decltype(auto) { - using REACT_IMPL::PrivateSignalLinkNodeInterface; + using REACT_IMPL::PrivateSignalLinkNodeInterface; using FuncNodeType = REACT_IMPL::SignalFuncNode::type, T1, Ts ...>; return std::make_shared( graphPtr, std::forward(func), - PrivateSignalLinkNodeInterface::GetLocalSignalNodePtr(graphPtr, dep1), PrivateSignalLinkNodeInterface::GetLocalSignalNodePtr(graphPtr, deps) ...); + PrivateSignalLinkNodeInterface::GetLocalNodePtr(graphPtr, dep1), PrivateSignalLinkNodeInterface::GetLocalNodePtr(graphPtr, deps) ...); } template auto CreateFuncNode(F&& func, const SignalBase& dep1, const SignalBase& ... deps) -> decltype(auto) { - using REACT_IMPL::PrivateNodeInterface; - return CreateFuncNode(PrivateNodeInterface::GraphPtr(dep1), std::forward(func), dep1, deps ...); + using REACT_IMPL::PrivateNodeInterface; + return CreateFuncNode(PrivateNodeInterface::GraphPtr(dep1), std::forward(func), dep1, deps ...); } private: @@ -240,11 +240,11 @@ class SignalLinkBase : public SignalBase using LinkNodeType = REACT_IMPL::SignalLinkNode; auto node = std::make_shared(graphPtr, PrivateNodeInterface::GraphPtr(input), PrivateNodeInterface::NodePtr(input)); - node->SetWeakSelfPtr(std::weak_ptr{ node }); - return node; + node->SetWeakSelfPtr(std::weak_ptr{ node }); + return node; } - friend struct REACT_IMPL::PrivateSignalLinkNodeInterface; + friend struct REACT_IMPL::PrivateSignalLinkNodeInterface; }; /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -272,7 +272,7 @@ class Signal : public SignalBase Signal::SignalBase( REACT_IMPL::CtorTag{ }, CreateFuncNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), std::forward(func), deps ...) ) { } - // Construct func signal with implicit group + // Construct func signal with implicit group template explicit Signal(F&& func, const SignalBase& ... deps) : Signal::SignalBase( REACT_IMPL::CtorTag{ }, CreateFuncNode(std::forward(func), deps ...) ) @@ -304,7 +304,7 @@ class Signal : public SignalBase Signal& operator=(Signal&& other) { Signal::SignalBase::operator=(std::move(other)); return *this; } - // Construct func signal with explicit group + // Construct func signal with explicit group template explicit Signal(const ReactiveGroupBase& group, F&& func, const SignalBase& ... deps) : Signal::SignalBase( REACT_IMPL::CtorTag{ }, CreateFuncNode(std::forward(func), deps ...) ) @@ -414,7 +414,7 @@ class SignalSlot : public SignalSlotBase SignalSlot::SignalSlotBase( REACT_IMPL::CtorTag{ }, CreateSlotNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), input) ) { } - // Construct with value + // Construct with value explicit SignalSlot(const SignalBase& input) : SignalSlot::SignalSlotBase( REACT_IMPL::CtorTag{ }, CreateSlotNode(REACT_IMPL::PrivateNodeInterface::GraphPtr(input), input) ) { } @@ -455,7 +455,7 @@ class SignalSlot : public SignalSlotBase SignalSlot::SignalSlotBase( REACT_IMPL::CtorTag{ }, CreateSlotNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), input) ) { } - // Construct with value + // Construct with value explicit SignalSlot(const SignalBase& input) : SignalSlot::SignalSlotBase( REACT_IMPL::CtorTag{ }, CreateSlotNode(REACT_IMPL::PrivateNodeInterface::GraphPtr(input), input) ) { } @@ -490,7 +490,7 @@ class SignalLink : public SignalLinkBase SignalLink::SignalLinkBase( REACT_IMPL::CtorTag{ }, CreateLinkNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), input) ) { } - // Construct with value + // Construct with value explicit SignalLink(const SignalBase& input) : SignalLink::SignalLinkBase( REACT_IMPL::CtorTag{ }, CreateLinkNode(REACT_IMPL::PrivateNodeInterface::GraphPtr(input), input) ) { } @@ -544,20 +544,20 @@ bool Equals(const SignalBase& lhs, const SignalBase& rhs) struct PrivateSignalLinkNodeInterface { - template - static auto GetLocalSignalNodePtr(const std::shared_ptr& targetGraph, const SignalBase& sig) -> std::shared_ptr> - { - const std::shared_ptr& sourceGraph = PrivateNodeInterface::GraphPtr(sig); - - if (sourceGraph == targetGraph) - { - return PrivateNodeInterface::NodePtr(sig); - } - else - { - return SignalLinkBase::CreateLinkNode(targetGraph, sig); - } - } + template + static auto GetLocalNodePtr(const std::shared_ptr& targetGraph, const SignalBase& sig) -> std::shared_ptr> + { + const std::shared_ptr& sourceGraph = PrivateNodeInterface::GraphPtr(sig); + + if (sourceGraph == targetGraph) + { + return PrivateNodeInterface::NodePtr(sig); + } + else + { + return SignalLinkBase::CreateLinkNode(targetGraph, sig); + } + } }; /****************************************/ REACT_IMPL_END /***************************************/ diff --git a/include/react/detail/ReactiveInput.h b/include/react/detail/ReactiveInput.h index dd2d101c..d156b9fb 100644 --- a/include/react/detail/ReactiveInput.h +++ b/include/react/detail/ReactiveInput.h @@ -654,8 +654,7 @@ class InputManager : } template - void AsyncTransaction(TransactionFlagsT flags, const WaitingStatePtrT& waitingStatePtr, - F&& func) + void AsyncTransaction(TransactionFlagsT flags, const WaitingStatePtrT& waitingStatePtr, F&& func) { if (waitingStatePtr != nullptr) waitingStatePtr->IncWaitCount(); @@ -693,9 +692,7 @@ class InputManager : } //IContinuationTarget - virtual void AsyncContinuation(TransactionFlagsT flags, - const WaitingStatePtrT& waitingStatePtr, - TransactionFuncT&& cont) override + virtual void AsyncContinuation(TransactionFlagsT flags, const WaitingStatePtrT& waitingStatePtr, TransactionFuncT&& cont) override { AsyncTransaction(flags, waitingStatePtr, std::move(cont)); } diff --git a/include/react/detail/graph/EventNodes.h b/include/react/detail/graph/EventNodes.h index f188e55c..7459af80 100644 --- a/include/react/detail/graph/EventNodes.h +++ b/include/react/detail/graph/EventNodes.h @@ -470,7 +470,7 @@ class EventJoinNode : public EventStreamNode> // All slots ready? apply( [this, &isReady] (Slot& ... slots) - { + { // Todo: combine return values instead REACT_EXPAND_PACK(CheckSlot(slots, isReady)); }, @@ -554,8 +554,8 @@ class EventLinkNode : public EventStreamNode this->UnregisterMe(); } - void SetWeakSelfPtr(const std::weak_ptr& self) - { linkOutput_.parent = self; } + void SetWeakSelfPtr(const std::weak_ptr& self) + { linkOutput_.parent = self; } virtual const char* GetNodeType() const override { return "EventLink"; } @@ -564,10 +564,10 @@ class EventLinkNode : public EventStreamNode { return 1; } virtual UpdateResult Update(TurnId turnId, int successorCount) override - { - this->SetPendingSuccessorCount(successorCount); - return UpdateResult::changed; - } + { + this->SetPendingSuccessorCount(successorCount); + return UpdateResult::changed; + } void SetEvents(EventLinkNode::EventStreamNode::StorageType&& events) { this->Events() = std::move(events); } @@ -576,19 +576,19 @@ class EventLinkNode : public EventStreamNode struct VirtualOutputNode : public ILinkOutputNode { VirtualOutputNode(const std::shared_ptr& srcGraphPtrIn, const std::shared_ptr>& depIn) : - parent( ), + parent( ), srcGraphPtr( srcGraphPtrIn ), dep( depIn ) { - nodeId = srcGraphPtr->RegisterNode(this, NodeCategory::linkoutput); - srcGraphPtr->OnNodeAttach(nodeId, dep->GetNodeId()); - } + nodeId = srcGraphPtr->RegisterNode(this, NodeCategory::linkoutput); + srcGraphPtr->OnNodeAttach(nodeId, dep->GetNodeId()); + } - ~VirtualOutputNode() - { - srcGraphPtr->OnNodeDetach(nodeId, dep->GetNodeId()); - srcGraphPtr->UnregisterNode(nodeId); - } + ~VirtualOutputNode() + { + srcGraphPtr->OnNodeDetach(nodeId, dep->GetNodeId()); + srcGraphPtr->UnregisterNode(nodeId); + } virtual const char* GetNodeType() const override { return "EventLinkOutput"; } @@ -598,30 +598,30 @@ class EventLinkNode : public EventStreamNode virtual UpdateResult Update(TurnId turnId, int successorCount) override { - return UpdateResult::changed; + return UpdateResult::changed; } virtual void CollectOutput(LinkOutputMap& output) override { - if (auto p = parent.lock()) - { - auto* rawPtr = p->GraphPtr().get(); - output[rawPtr].push_back( - [storedParent = std::move(p), storedEvents = dep->Events()] () mutable - { - NodeId nodeId = storedParent->GetNodeId(); - auto& graphPtr = storedParent->GraphPtr(); - - graphPtr->AddInput(nodeId, - [&storedParent, &storedEvents] - { - storedParent->SetEvents(std::move(storedEvents)); - }); - }); - } - } - - std::weak_ptr parent; + if (auto p = parent.lock()) + { + auto* rawPtr = p->GraphPtr().get(); + output[rawPtr].push_back( + [storedParent = std::move(p), storedEvents = dep->Events()] () mutable + { + NodeId nodeId = storedParent->GetNodeId(); + auto& graphPtr = storedParent->GraphPtr(); + + graphPtr->AddInput(nodeId, + [&storedParent, &storedEvents] + { + storedParent->SetEvents(std::move(storedEvents)); + }); + }); + } + } + + std::weak_ptr parent; NodeId nodeId; diff --git a/include/react/detail/graph/ObserverNodes.h b/include/react/detail/graph/ObserverNodes.h index f8887d8b..d4f3968a 100644 --- a/include/react/detail/graph/ObserverNodes.h +++ b/include/react/detail/graph/ObserverNodes.h @@ -158,7 +158,7 @@ class SyncedEventObserverNode : public ObserverNode virtual UpdateResult Update(TurnId turnId, int successorCount) override { // Updates might be triggered even if only sync nodes changed. Ignore those. - if (events_->Events().empty()) + if (subject_->Events().empty()) return UpdateResult::unchanged; apply([this] (const auto& ... syncs) { func_(EventRange( this->subject_->Events() ), syncs->Value() ...); }, syncHolder_); diff --git a/include/react/detail/graph/SignalNodes.h b/include/react/detail/graph/SignalNodes.h index d084945d..cb66531d 100644 --- a/include/react/detail/graph/SignalNodes.h +++ b/include/react/detail/graph/SignalNodes.h @@ -319,8 +319,8 @@ class SignalLinkNode : public SignalNode this->UnregisterMe(); } - void SetWeakSelfPtr(const std::weak_ptr& self) - { linkOutput_.parent = self; } + void SetWeakSelfPtr(const std::weak_ptr& self) + { linkOutput_.parent = self; } virtual const char* GetNodeType() const override { return "SignalLink"; } @@ -343,19 +343,19 @@ class SignalLinkNode : public SignalNode struct VirtualOutputNode : public ILinkOutputNode { VirtualOutputNode(const std::shared_ptr& srcGraphPtrIn, const std::shared_ptr>& depIn) : - parent( ), + parent( ), srcGraphPtr( srcGraphPtrIn ), dep( depIn ) { - nodeId = srcGraphPtr->RegisterNode(this, NodeCategory::linkoutput); - srcGraphPtr->OnNodeAttach(nodeId, dep->GetNodeId()); - } + nodeId = srcGraphPtr->RegisterNode(this, NodeCategory::linkoutput); + srcGraphPtr->OnNodeAttach(nodeId, dep->GetNodeId()); + } - ~VirtualOutputNode() - { - srcGraphPtr->OnNodeDetach(nodeId, dep->GetNodeId()); - srcGraphPtr->UnregisterNode(nodeId); - } + ~VirtualOutputNode() + { + srcGraphPtr->OnNodeDetach(nodeId, dep->GetNodeId()); + srcGraphPtr->UnregisterNode(nodeId); + } virtual const char* GetNodeType() const override { return "SignalLinkOutput"; } @@ -370,25 +370,25 @@ class SignalLinkNode : public SignalNode virtual void CollectOutput(LinkOutputMap& output) override { - if (auto p = parent.lock()) - { - auto* rawPtr = p->GraphPtr().get(); - output[rawPtr].push_back( - [storedParent = std::move(p), storedValue = dep->Value()] - { - NodeId nodeId = storedParent->GetNodeId(); - auto& graphPtr = storedParent->GraphPtr(); - - graphPtr->AddInput(nodeId, - [&storedParent, &storedValue] - { - storedParent->SetValue(std::move(storedValue)); - }); - }); - } - } - - std::weak_ptr parent; + if (auto p = parent.lock()) + { + auto* rawPtr = p->GraphPtr().get(); + output[rawPtr].push_back( + [storedParent = std::move(p), storedValue = dep->Value()] + { + NodeId nodeId = storedParent->GetNodeId(); + auto& graphPtr = storedParent->GraphPtr(); + + graphPtr->AddInput(nodeId, + [&storedParent, &storedValue] + { + storedParent->SetValue(std::move(storedValue)); + }); + }); + } + } + + std::weak_ptr parent; NodeId nodeId; From 33cab90c56aa3168720ea432b1ad2a95aa5e9d81 Mon Sep 17 00:00:00 2001 From: schlangster Date: Mon, 12 Dec 2016 18:35:46 +0100 Subject: [PATCH 38/75] fixes --- include/react/Algorithm.h | 10 ++-- include/react/detail/graph/PropagationST.h | 62 ++++++++-------------- 2 files changed, 27 insertions(+), 45 deletions(-) diff --git a/include/react/Algorithm.h b/include/react/Algorithm.h index 9a033559..6a0037a2 100644 --- a/include/react/Algorithm.h +++ b/include/react/Algorithm.h @@ -79,7 +79,7 @@ auto Monitor(const SignalBase& signal) -> Event using REACT_IMPL::PrivateNodeInterface; using REACT_IMPL::CtorTag; - const auto& graphPtr = PrivateNodeInterface::GraphPtr(evnt); + const auto& graphPtr = PrivateNodeInterface::GraphPtr(signal); return Event( CtorTag{ }, std::make_shared>( graphPtr, PrivateSignalLinkNodeInterface::GetLocalNodePtr(graphPtr, signal)) ); @@ -197,8 +197,8 @@ auto Snapshot(const ReactiveGroupBase& group, const SignalBase& signal, const const auto& graphPtr = PrivateReactiveGroupInterface::GraphPtr(group); - return Event( CtorTag{ }, std::make_shared>( - graphPtr, PrivateNodeInterface::NodePtr(signal), PrivateNodeInterface::NodePtr(evnt)) ); + return Signal( CtorTag{ }, std::make_shared>( + graphPtr, PrivateSignalLinkNodeInterface::GetLocalNodePtr(graphPtr, signal), PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, evnt)) ); } template @@ -212,7 +212,7 @@ auto Snapshot(const SignalBase& signal, const EventBase& evnt) -> Signal( CtorTag{ }, std::make_shared>( + return Signal( CtorTag{ }, std::make_shared>( graphPtr, PrivateSignalLinkNodeInterface::GetLocalNodePtr(graphPtr, signal), PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, evnt)) ); } @@ -231,7 +231,7 @@ auto Pulse(const ReactiveGroupBase& group, const SignalBase& signal, const Ev const auto& graphPtr = PrivateReactiveGroupInterface::GraphPtr(group); return Event( CtorTag{ }, std::make_shared>( - graphPtr, PrivateSignalLinkNodeInterface::NodePtr(graphPtr, signal), PrivateEventLinkNodeInterface::NodePtr(graphPtr, evnt)) ); + graphPtr, PrivateSignalLinkNodeInterface::GetLocalNodePtr(graphPtr, signal), PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, evnt)) ); } template diff --git a/include/react/detail/graph/PropagationST.h b/include/react/detail/graph/PropagationST.h index 182cfcd0..4b8f2441 100644 --- a/include/react/detail/graph/PropagationST.h +++ b/include/react/detail/graph/PropagationST.h @@ -44,7 +44,7 @@ class TransactionQueue template void Push(TransactionFlags flags, F&& transaction) { - transactions_.push(StoredTransaction{ flags, std::forward(transaction) }); + transactions_.push(StoredTransaction{ flags, std::forward(transaction) }); if (count_.fetch_add(1, std::memory_order_relaxed) == 0) tbb::task::enqueue(*new(tbb::task::allocate_root()) WorkerTask(*this)); @@ -117,7 +117,7 @@ class ReactiveGraph NodeData(IReactiveNode* nodePtrIn, NodeCategory categoryIn) : nodePtr( nodePtrIn ), category(categoryIn) - { } + { } NodeCategory category = NodeCategory::normal; @@ -238,8 +238,8 @@ void ReactiveGraph::AddInput(NodeId nodeId, F&& inputCallback) if (! scheduledNodes_.IsEmpty()) Propagate(); - if (! scheduledLinkOutputs_.empty()) - UpdateLinkNodes(); + if (! scheduledLinkOutputs_.empty()) + UpdateLinkNodes(); } } } @@ -303,12 +303,12 @@ void ReactiveGraph::Propagate() continue; } - // Special handling for link output nodes. They have no successors and they don't have to be updated. - if (node.category == NodeCategory::linkoutput) - { - static_cast(node.nodePtr)->CollectOutput(scheduledLinkOutputs_); - continue; - } + // Special handling for link output nodes. They have no successors and they don't have to be updated. + if (node.category == NodeCategory::linkoutput) + { + static_cast(node.nodePtr)->CollectOutput(scheduledLinkOutputs_); + continue; + } int successorCount = node.successors.size(); @@ -324,35 +324,17 @@ void ReactiveGraph::Propagate() void ReactiveGraph::UpdateLinkNodes() { - for (auto& e : scheduledLinkOutputs_) - { - e.first->EnqueueTransaction(TransactionFlags::none, - [inputs = std::move(e.second)] - { - for (auto& callback : inputs) - callback(); - }); - } - - scheduledLinkOutputs_.clear(); - - /*using ElementType = std::pair; - - auto from = scheduledLinkOutputs_.begin(); - auto to = scheduledLinkOutputs_.end(); - - for (auto it = from; it != to; ++it) - { - ReactiveGraph* graphPtr = it->first; - auto p = std::partition(it, to, [=] (ReactiveGraph* e) { return e == graphPtr }); - - for (auto it2 = p; it2 != to; ++it2) - { - graphPtr->EnqueueLinkTransaction(); - } - } - - scheduledLinkOutputs_.clear();*/ + for (auto& e : scheduledLinkOutputs_) + { + e.first->EnqueueTransaction(TransactionFlags::none, + [inputs = std::move(e.second)] + { + for (auto& callback : inputs) + callback(); + }); + } + + scheduledLinkOutputs_.clear(); } void ReactiveGraph::ScheduleSuccessors(NodeData& node) @@ -364,7 +346,7 @@ void ReactiveGraph::ScheduleSuccessors(NodeData& node) if (!succ.queued) { succ.queued = true; - scheduledNodes_.Push(succId, succ.level); + scheduledNodes_.Push(succId, succ.level); } } } From f5454397a9e82ac131738e36e47ae57a45704b86 Mon Sep 17 00:00:00 2001 From: schlangster Date: Mon, 12 Dec 2016 23:01:18 +0100 Subject: [PATCH 39/75] example + benchmark fixes, wip --- benchmarks/src/BenchmarkBase.h | 15 +---- benchmarks/src/BenchmarkGrid.h | 60 +++++++++----------- benchmarks/src/Main.cpp | 17 +----- examples/src/BasicAlgorithms.cpp | 10 ++-- examples/src/BasicEvents.cpp | 38 +------------ examples/src/BasicObservers.cpp | 2 +- examples/src/BasicSignals.cpp | 50 +++-------------- examples/src/BasicSynchronization.cpp | 25 ++++++--- include/react/Group.h | 62 ++------------------- include/react/detail/IReactiveGraph.h | 2 +- include/react/detail/graph/AlgorithmNodes.h | 17 +++--- include/react/detail/graph/EventNodes.h | 22 ++++---- include/react/detail/graph/ObserverNodes.h | 6 +- include/react/detail/graph/PropagationST.h | 8 +-- include/react/detail/graph/SignalNodes.h | 12 ++-- 15 files changed, 103 insertions(+), 243 deletions(-) diff --git a/benchmarks/src/BenchmarkBase.h b/benchmarks/src/BenchmarkBase.h index 4b65306a..528a8489 100644 --- a/benchmarks/src/BenchmarkBase.h +++ b/benchmarks/src/BenchmarkBase.h @@ -55,18 +55,6 @@ inline const std::string CurrentDateTime() return buf; } -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// BenchmarkBase -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -class BenchmarkBase -{ -public: - typedef D Domain; - - double Run(); -}; - /////////////////////////////////////////////////////////////////////////////////////////////////// /// RunBenchmark /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -118,8 +106,7 @@ template < int RUN_COUNT, template class TBenchmark, - typename TParams, - typename ... Ds + typename TParams > void RunBenchmarkClass(const char* name, std::ostream& out, const TParams& params) { diff --git a/benchmarks/src/BenchmarkGrid.h b/benchmarks/src/BenchmarkGrid.h index d719afaa..29afe312 100644 --- a/benchmarks/src/BenchmarkGrid.h +++ b/benchmarks/src/BenchmarkGrid.h @@ -21,47 +21,42 @@ using namespace react; /////////////////////////////////////////////////////////////////////////////////////////////////// /// GridGraphGenerator /////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename D, - typename TValue -> +template class GridGraphGenerator { public: - using MySignal = Signal; + using SignalType = Signal; - using Func1T = std::function; - using Func2T = std::function; + using Func1T = std::function; + using Func2T = std::function; - using SignalVectT = std::vector; - using WidthVectT = std::vector; + using SignalVectType = std::vector; - SignalVectT InputSignals; - SignalVectT OutputSignals; + SignalVectType inputSignals; + SignalVectType outputSignals; - Func1T Function1; - Func2T Function2; + Func1T function1; + Func2T function2; - WidthVectT Widths; + std::vector widths; void Generate() { - assert(InputSignals.size() >= 1); - assert(Widths.size() >= 1); + assert(inputSignals.size() >= 1); + assert(widths.size() >= 1); - SignalVectT buf1 = InputSignals; - SignalVectT buf2; + SignalVectType buf1 = std::move(inputSignals); + SignalVectType buf2; SignalVectT* curBuf = &buf1; SignalVectT* nextBuf = &buf2; - size_t curWidth = InputSignals.size(); + size_t curWidth = inputSignals.size(); size_t nodeCount = 1; nodeCount += curWidth; - for (auto targetWidth : Widths) + for (auto targetWidth : widths) { while (curWidth != targetWidth) { @@ -110,8 +105,8 @@ class GridGraphGenerator //printf ("NODE COUNT %d\n", nodeCount); - OutputSignals.clear(); - OutputSignals.insert(OutputSignals.begin(), curBuf->begin(), curBuf->end()); + outputSignals.clear(); + outputSignals.insert(outputSignals.begin(), curBuf->begin(), curBuf->end()); } }; @@ -135,22 +130,21 @@ struct BenchmarkParams_Grid const int K; }; -template -struct Benchmark_Grid : public BenchmarkBase +struct Benchmark_Grid { - double Run(const BenchmarkParams_Grid& params) + double Run(const BenchmarkParams_Grid& params, const ReactiveGroupBase& group) { - auto in = MakeVar(1); + VarSignal in{ group, 1 }; - GridGraphGenerator generator; + GridGraphGenerator generator; - generator.InputSignals.push_back(in); + generator.inputSignals.push_back(in); - generator.Widths.push_back(params.N); - generator.Widths.push_back(1); + generator.widths.push_back(params.N); + generator.widths.push_back(1); - generator.Function1 = [] (int a) { return a; }; - generator.Function2 = [] (int a, int b) { return a + b; }; + generator.function1 = [] (int a) { return a; }; + generator.function2 = [] (int a, int b) { return a + b; }; generator.Generate(); diff --git a/benchmarks/src/Main.cpp b/benchmarks/src/Main.cpp index 93a79d78..cbf5aaca 100644 --- a/benchmarks/src/Main.cpp +++ b/benchmarks/src/Main.cpp @@ -17,31 +17,16 @@ #include "BenchmarkSequence.h" #include "BenchmarkLifeSim.h" -#include "react/Domain.h" +#include "react/Group.h" #include "react/Signal.h" #include "react/Algorithm.h" #include "react/common/Util.h" -#include "react/logging/EventLog.h" - -#include "react/engine/ToposortEngine.h" -#include "react/engine/PulsecountEngine.h" -#include "react/engine/SubtreeEngine.h" /////////////////////////////////////////////////////////////////////////////////////////////////// namespace { using namespace react; -REACTIVE_DOMAIN(ToposortSTDomain, sequential, ToposortEngine) -REACTIVE_DOMAIN(ToposortDomain, parallel, ToposortEngine) -REACTIVE_DOMAIN(PulsecountDomain, parallel, PulsecountEngine) -REACTIVE_DOMAIN(SubtreeDomain, parallel, SubtreeEngine) - -REACTIVE_DOMAIN(ToposortSTDomainConc, sequential_concurrent, ToposortEngine) -REACTIVE_DOMAIN(ToposortDomainConc, parallel_concurrent, ToposortEngine) -REACTIVE_DOMAIN(PulsecountDomainConc, parallel_concurrent, PulsecountEngine) -REACTIVE_DOMAIN(SubtreeDomainConc, parallel_concurrent, SubtreeEngine) - void runBenchmarkGrid(std::ostream& out) { RUN_BENCHMARK(out, 5, Benchmark_Grid, BenchmarkParams_Grid(20, 10000), diff --git a/examples/src/BasicAlgorithms.cpp b/examples/src/BasicAlgorithms.cpp index 1e84305d..a11dbdb9 100644 --- a/examples/src/BasicAlgorithms.cpp +++ b/examples/src/BasicAlgorithms.cpp @@ -66,8 +66,8 @@ namespace example2 struct Employee { - VarSignal name { string( "Bob" ), group }; - VarSignal salary { 3000, group }; + VarSignal name { group, string( "Bob" ) }; + VarSignal salary { group, 3000 }; }; void Run() @@ -213,8 +213,8 @@ namespace example5 public: EventSource update{ group }; - VarSignal delta{ 1, group }; - VarSignal start{ 0, group }; + VarSignal delta{ group, 1 }; + VarSignal start{ group, 0 }; Signal count{ Iterate(start.Value(), DoCounterLoop, update, delta, start) }; }; @@ -276,7 +276,7 @@ namespace example6 public: EventSource input{ group }; - VarSignal threshold{ 42, group }; + VarSignal threshold{ group, 42 }; Signal> allSamples{ Iterate>(vector{ }, DoIterateAllSamples, input) }; diff --git a/examples/src/BasicEvents.cpp b/examples/src/BasicEvents.cpp index 0f4f3f06..b9a7cfbd 100644 --- a/examples/src/BasicEvents.cpp +++ b/examples/src/BasicEvents.cpp @@ -237,46 +237,12 @@ namespace example5 /////////////////////////////////////////////////////////////////////////////////////////////////// int main() { - using namespace std; - using namespace react; - - ReactiveGroup<> group; - - auto ev1 = EventSource( group ); - auto ev2 = EventSource( group ); - - auto slot1 = EventSlot( ev1, group ); - auto slot2 = EventSlot( ev1, group ); - - Observer<> obs1( - [] (EventRange in) - { - for (int e : in) - cout << e << endl; - }, slot1); - - Observer<> obs2( - [] (EventRange in) - { - for (int e : in) - cout << e << endl; - }, slot2); - - ev1 << 10 << 20 << 30; - ev2 << 11 << 22 << 33; - - slot1.Set(ev2); - slot2.Set(ev2); - - ev1 << 10 << 20 << 30; - ev2 << 11 << 22 << 33; - - /*example1::v1::Run(); + example1::v1::Run(); example1::v2::Run(); example2::Run(); example3::Run(); example4::Run(); - example5::Run();*/ + example5::Run(); return 0; } \ No newline at end of file diff --git a/examples/src/BasicObservers.cpp b/examples/src/BasicObservers.cpp index 0a282528..c81cb372 100644 --- a/examples/src/BasicObservers.cpp +++ b/examples/src/BasicObservers.cpp @@ -22,7 +22,7 @@ namespace example1 ReactiveGroup<> group; - VarSignal x( 1, group ); + VarSignal x( group, 1 ); void Run() { diff --git a/examples/src/BasicSignals.cpp b/examples/src/BasicSignals.cpp index 44369987..fc52eb68 100644 --- a/examples/src/BasicSignals.cpp +++ b/examples/src/BasicSignals.cpp @@ -32,8 +32,8 @@ namespace example1 ReactiveGroup<> group; // The two words - VarSignal firstWord( string("Change"), group ); - VarSignal secondWord( string("me!"), group ); + VarSignal firstWord( group, string("Change") ); + VarSignal secondWord( group, string("me!") ); // A signal that concatenates both words Signal bothWords(ConcatFunc, firstWord, secondWord); @@ -66,7 +66,7 @@ namespace example2 ReactiveGroup<> group; - VarSignal x( 1, group ); + VarSignal x( group, 1 ); Signal xAbs( [] (int v) { return abs(v); }, x); @@ -100,8 +100,8 @@ namespace example3 ReactiveGroup<> group; - VarSignal a( 1, group ); - VarSignal b( 1, group ); + VarSignal a( group, 1 ); + VarSignal b( group, 1 ); Signal x( sumFunc, a, b ); Signal y( sumFunc, a, b ); @@ -186,8 +186,8 @@ namespace example5 } // Input operands - VarSignal a( 1, group ); - VarSignal b( 2, group ); + VarSignal a( group, 1 ); + VarSignal b( group, 2 ); // The expression vector Signal expressions( @@ -218,43 +218,11 @@ namespace example5 /////////////////////////////////////////////////////////////////////////////////////////////////// int main() { - using namespace std; - using namespace react; - - ReactiveGroup<> group; - - auto sig1 = VarSignal( 10, group ); - auto sig2 = VarSignal( 22, group ); - - auto slot1 = SignalSlot( sig1, group ); - auto slot2 = SignalSlot( sig1, group ); - - printf("%d\n", slot1.Value()); - printf("%d\n", slot2.Value()); - - slot1.Set(sig2); - slot2.Set(sig2); - - printf("%d\n", slot1.Value()); - printf("%d\n", slot2.Value()); - - group.DoTransaction([&] - { - slot1.Set(sig2); - slot2.Set(sig2); - }); - - group.EnqueueTransaction([&] - { - slot1.Set(sig2); - slot2.Set(sig2); - }); - - /*example1::Run(); + example1::Run(); example2::Run(); example3::Run(); example4::Run(); - example5::Run();*/ + example5::Run(); return 0; } \ No newline at end of file diff --git a/examples/src/BasicSynchronization.cpp b/examples/src/BasicSynchronization.cpp index 4a7f6529..a79f87ce 100644 --- a/examples/src/BasicSynchronization.cpp +++ b/examples/src/BasicSynchronization.cpp @@ -21,25 +21,36 @@ namespace example1 using namespace react; using namespace std; - REACTIVE_DOMAIN(D, sequential_concurrent) + ReactiveGroup<> group; class Sensor { public: - USING_REACTIVE_DOMAIN(D) + Sensor(const Sensor&) = default; + Sensor& operator=(const Sensor&) = default; + Sensor(Sensor&&) = default; + Sensor& operator=(Sensor&&) = default; - EventSourceT Samples = MakeEventSource(); + explicit Sensor(const ReactiveGroup<>& group) : + Samples( group ) + { } + + EventSource Samples; }; void Run() { cout << "Example 1 - Asynchronous transactions" << endl; - Sensor mySensor; + Sensor mySensor( group ); - Observe(mySensor.Samples, [] (int v) { - cout << v << endl; - }); + Observer<> obs( + [&] (EventRange<> in) + { + for (auto t : in) + cout << v << endl; + }, + mySensor.Samples); TransactionStatus status; diff --git a/include/react/Group.h b/include/react/Group.h index fc5e49f1..ca2c02f0 100644 --- a/include/react/Group.h +++ b/include/react/Group.h @@ -28,8 +28,6 @@ struct CtorTag { }; /*****************************************/ REACT_BEGIN /*****************************************/ - - #if 0 /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -84,54 +82,6 @@ class TransactionStatus friend void AsyncTransaction(TransactionFlagsT flags, TransactionStatus& status, F&& func); }; -/////////////////////////////////////////////////////////////////////////////////////////////// -/// AsyncTransaction -/////////////////////////////////////////////////////////////////////////////////////////////// -template -void AsyncTransaction(F&& func) -{ - static_assert(D::is_concurrent, - "AsyncTransaction: Domain does not support concurrent input."); - - using REACT_IMPL::DomainSpecificInputManager; - DomainSpecificInputManager::Instance() - .AsyncTransaction(0, nullptr, std::forward(func)); -} - -template -void AsyncTransaction(TransactionFlags flags, F&& func) -{ - static_assert(D::is_concurrent, - "AsyncTransaction: Domain does not support concurrent input."); - - using REACT_IMPL::DomainSpecificInputManager; - DomainSpecificInputManager::Instance() - .AsyncTransaction(flags, nullptr, std::forward(func)); -} - -template -void AsyncTransaction(TransactionStatus& status, F&& func) -{ - static_assert(D::is_concurrent, - "AsyncTransaction: Domain does not support concurrent input."); - - using REACT_IMPL::DomainSpecificInputManager; - - DomainSpecificInputManager::Instance() - .AsyncTransaction(0, status.statePtr_, std::forward(func)); -} - -template -void AsyncTransaction(TransactionFlagsT flags, TransactionStatus& status, F&& func) -{ - static_assert(D::is_concurrent, - "AsyncTransaction: Domain does not support concurrent input."); - - using REACT_IMPL::DomainSpecificInputManager; - DomainSpecificInputManager::Instance() - .AsyncTransaction(flags, status.statePtr_, std::forward(func)); -} - #endif /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -146,12 +96,6 @@ class ReactiveGroupBase graphPtr_( std::make_shared() ) { } - ReactiveGroupBase(const ReactiveGroupBase&) = default; - ReactiveGroupBase& operator=(const ReactiveGroupBase&) = default; - - ReactiveGroupBase(ReactiveGroupBase&& other) = default; - ReactiveGroupBase& operator=(ReactiveGroupBase&& other) = default; - ~ReactiveGroupBase() = default; template @@ -167,6 +111,12 @@ class ReactiveGroupBase { graphPtr_->EnqueueTransaction(flags, std::forward(func)); } protected: + ReactiveGroupBase(const ReactiveGroupBase&) = default; + ReactiveGroupBase& operator=(const ReactiveGroupBase&) = default; + + ReactiveGroupBase(ReactiveGroupBase&& other) = default; + ReactiveGroupBase& operator=(ReactiveGroupBase&& other) = default; + auto GraphPtr() -> std::shared_ptr& { return graphPtr_; } diff --git a/include/react/detail/IReactiveGraph.h b/include/react/detail/IReactiveGraph.h index 2ac8f291..85f3d253 100644 --- a/include/react/detail/IReactiveGraph.h +++ b/include/react/detail/IReactiveGraph.h @@ -59,7 +59,7 @@ struct IReactiveNode virtual const char* GetNodeType() const = 0; - virtual UpdateResult Update(TurnId turnId, int successorCount) = 0; + virtual UpdateResult Update(TurnId turnId, size_t successorCount) = 0; virtual int GetDependencyCount() const = 0; }; diff --git a/include/react/detail/graph/AlgorithmNodes.h b/include/react/detail/graph/AlgorithmNodes.h index 62ff5c9a..274581fd 100644 --- a/include/react/detail/graph/AlgorithmNodes.h +++ b/include/react/detail/graph/AlgorithmNodes.h @@ -101,7 +101,7 @@ class IterateNode : public SignalNode this->UnregisterMe(); } - virtual UpdateResult Update(TurnId turnId, int successorCount) override + virtual UpdateResult Update(TurnId turnId, size_t successorCount) override { S newValue = func_(EventRange( events_->Events() ), this->Value()); @@ -153,7 +153,7 @@ class IterateByRefNode : public SignalNode this->UnregisterMe(); } - virtual UpdateResult Update(TurnId turnId, int successorCount) override + virtual UpdateResult Update(TurnId turnId, size_t successorCount) override { func_(EventRange( events_->Events() ), this->Value()); @@ -201,7 +201,7 @@ class SyncedIterateNode : public SignalNode this->UnregisterMe(); } - virtual UpdateResult Update(TurnId turnId, int successorCount) override + virtual UpdateResult Update(TurnId turnId, size_t successorCount) override { // Updates might be triggered even if only sync nodes changed. Ignore those. if (events_->Events().empty()) @@ -267,7 +267,7 @@ class SyncedIterateByRefNode : public SignalNode this->UnregisterMe(); } - virtual UpdateResult Update(TurnId turnId, int successorCount) override + virtual UpdateResult Update(TurnId turnId, size_t successorCount) override { // Updates might be triggered even if only sync nodes changed. Ignore those. if (events_->Events().empty()) @@ -281,7 +281,6 @@ class SyncedIterateByRefNode : public SignalNode syncHolder_); events_->DecrementPendingSuccessorCount(); - this->SetPendingSuccessorCount(successorCount); return UpdateResult::changed; } @@ -325,7 +324,7 @@ class HoldNode : public SignalNode virtual const char* GetNodeType() const override { return "HoldNode"; } - virtual UpdateResult Update(TurnId turnId, int successorCount) override + virtual UpdateResult Update(TurnId turnId, size_t successorCount) override { bool changed = false; @@ -379,7 +378,7 @@ class SnapshotNode : public SignalNode this->UnregisterMe(); } - virtual UpdateResult Update(TurnId turnId, int successorCount) override + virtual UpdateResult Update(TurnId turnId, size_t successorCount) override { bool changed = false; @@ -434,7 +433,7 @@ class MonitorNode : public EventStreamNode this->UnregisterMe(); } - virtual UpdateResult Update(TurnId turnId, int successorCount) override + virtual UpdateResult Update(TurnId turnId, size_t successorCount) override { this->Events().push_back(target_->Value()); @@ -477,7 +476,7 @@ class PulseNode : public EventStreamNode this->UnregisterMe(); } - virtual UpdateResult Update(TurnId turnId, int successorCount) override + virtual UpdateResult Update(TurnId turnId, size_t successorCount) override { for (size_t i=0; iEvents().size(); i++) this->Events().push_back(target_->Value()); diff --git a/include/react/detail/graph/EventNodes.h b/include/react/detail/graph/EventNodes.h index 7459af80..374038fb 100644 --- a/include/react/detail/graph/EventNodes.h +++ b/include/react/detail/graph/EventNodes.h @@ -98,7 +98,7 @@ class EventStreamNode : public NodeBase { return events_; } - void SetPendingSuccessorCount(int count) + void SetPendingSuccessorCount(size_t count) { if (count == 0) { @@ -127,7 +127,7 @@ class EventStreamNode : public NodeBase private: StorageType events_; - std::atomic pendingSuccessorCount_ = 0; + std::atomic pendingSuccessorCount_ = 0; }; /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -150,7 +150,7 @@ class EventSourceNode : public EventStreamNode virtual int GetDependencyCount() const override { return 0; } - virtual UpdateResult Update(TurnId turnId, int successorCount) override + virtual UpdateResult Update(TurnId turnId, size_t successorCount) override { if (! this->Events().empty()) { @@ -189,7 +189,7 @@ class EventMergeNode : public EventStreamNode this->UnregisterMe(); } - virtual UpdateResult Update(TurnId turnId, int successorCount) override + virtual UpdateResult Update(TurnId turnId, size_t successorCount) override { apply([this] (const auto& ... deps) { REACT_EXPAND_PACK(MergeFromDep(deps)); }, depHolder_); @@ -254,7 +254,7 @@ class EventSlotNode : public EventStreamNode virtual int GetDependencyCount() const override { return 2; } - virtual UpdateResult Update(TurnId turnId, int successorCount) override + virtual UpdateResult Update(TurnId turnId, size_t successorCount) override { this->Events().insert(this->Events().end(), slotInput_.dep->Events().begin(), slotInput_.dep->Events().end()); @@ -291,7 +291,7 @@ class EventSlotNode : public EventStreamNode virtual int GetDependencyCount() const override { return 0; } - virtual UpdateResult Update(TurnId turnId, int successorCount) override + virtual UpdateResult Update(TurnId turnId, size_t successorCount) override { if (dep != newDep) { @@ -342,7 +342,7 @@ class EventProcessingNode : public EventStreamNode this->UnregisterMe(); } - virtual UpdateResult Update(TurnId turnId, int successorCount) override + virtual UpdateResult Update(TurnId turnId, size_t successorCount) override { func_(EventRange( dep_->Events() ), std::back_inserter(this->Events())); @@ -397,7 +397,7 @@ class SyncedEventProcessingNode : public EventStreamNode this->UnregisterMe(); } - virtual UpdateResult Update(TurnId turnId, int successorCount) override + virtual UpdateResult Update(TurnId turnId, size_t successorCount) override { // Updates might be triggered even if only sync nodes changed. Ignore those. if (dep_->Events().empty()) @@ -458,7 +458,7 @@ class EventJoinNode : public EventStreamNode> this->UnregisterMe(); } - virtual UpdateResult Update(TurnId turnId, int successorCount) override + virtual UpdateResult Update(TurnId turnId, size_t successorCount) override { // Move events into buffers. apply([this, turnId] (Slot& ... slots) { REACT_EXPAND_PACK(FetchBuffer(turnId, slots)); }, slots_); @@ -563,7 +563,7 @@ class EventLinkNode : public EventStreamNode virtual int GetDependencyCount() const override { return 1; } - virtual UpdateResult Update(TurnId turnId, int successorCount) override + virtual UpdateResult Update(TurnId turnId, size_t successorCount) override { this->SetPendingSuccessorCount(successorCount); return UpdateResult::changed; @@ -596,7 +596,7 @@ class EventLinkNode : public EventStreamNode virtual int GetDependencyCount() const override { return 1; } - virtual UpdateResult Update(TurnId turnId, int successorCount) override + virtual UpdateResult Update(TurnId turnId, size_t successorCount) override { return UpdateResult::changed; } diff --git a/include/react/detail/graph/ObserverNodes.h b/include/react/detail/graph/ObserverNodes.h index d4f3968a..d383d341 100644 --- a/include/react/detail/graph/ObserverNodes.h +++ b/include/react/detail/graph/ObserverNodes.h @@ -69,7 +69,7 @@ class SignalObserverNode : public ObserverNode virtual int GetDependencyCount() const override { return sizeof...(TDeps); } - virtual UpdateResult Update(TurnId turnId, int successorCount) override + virtual UpdateResult Update(TurnId turnId, size_t successorCount) override { apply([this] (const auto& ... deps) { this->func_(deps->Value() ...); }, depHolder_); return UpdateResult::unchanged; @@ -110,7 +110,7 @@ class EventObserverNode : public ObserverNode virtual int GetDependencyCount() const override { return 1; } - virtual UpdateResult Update(TurnId turnId, int successorCount) override + virtual UpdateResult Update(TurnId turnId, size_t successorCount) override { func_(EventRange( subject_->Events() )); subject_->DecrementPendingSuccessorCount(); @@ -155,7 +155,7 @@ class SyncedEventObserverNode : public ObserverNode virtual int GetDependencyCount() const override { return 1 + sizeof...(TSyncs); } - virtual UpdateResult Update(TurnId turnId, int successorCount) override + virtual UpdateResult Update(TurnId turnId, size_t successorCount) override { // Updates might be triggered even if only sync nodes changed. Ignore those. if (subject_->Events().empty()) diff --git a/include/react/detail/graph/PropagationST.h b/include/react/detail/graph/PropagationST.h index 4b8f2441..dbce7777 100644 --- a/include/react/detail/graph/PropagationST.h +++ b/include/react/detail/graph/PropagationST.h @@ -227,7 +227,7 @@ void ReactiveGraph::AddInput(NodeId nodeId, F&& inputCallback) } else { - int successorCount = node.successors.size(); + size_t successorCount = node.successors.size(); // Update the node. This applies the input buffer to the node value and checks if it changed. if (nodePtr->Update(0, successorCount) == UpdateResult::changed) @@ -258,7 +258,7 @@ void ReactiveGraph::DoTransaction(F&& transactionCallback) auto& node = nodeData_[nodeId]; auto* nodePtr = node.nodePtr; - int successorCount = node.successors.size(); + size_t successorCount = node.successors.size(); if (nodePtr->Update(0, successorCount) == UpdateResult::changed) { @@ -310,9 +310,9 @@ void ReactiveGraph::Propagate() continue; } - int successorCount = node.successors.size(); + size_t successorCount = node.successors.size(); - if (nodePtr->Update(0, successorCount) == UpdateResult::changed) + if (nodePtr->Update(0u, successorCount) == UpdateResult::changed) { ScheduleSuccessors(node); } diff --git a/include/react/detail/graph/SignalNodes.h b/include/react/detail/graph/SignalNodes.h index cb66531d..4dbd8574 100644 --- a/include/react/detail/graph/SignalNodes.h +++ b/include/react/detail/graph/SignalNodes.h @@ -87,7 +87,7 @@ class VarSignalNode : public SignalNode virtual int GetDependencyCount() const override { return 0; } - virtual UpdateResult Update(TurnId turnId, int successorCount) override + virtual UpdateResult Update(TurnId turnId, size_t successorCount) override { if (isInputAdded_) { @@ -182,7 +182,7 @@ class SignalFuncNode : public SignalNode virtual int GetDependencyCount() const override { return sizeof...(TDeps); } - virtual UpdateResult Update(TurnId turnId, int successorCount) override + virtual UpdateResult Update(TurnId turnId, size_t successorCount) override { bool changed = false; @@ -239,7 +239,7 @@ class SignalSlotNode : public SignalNode virtual int GetDependencyCount() const override { return 2; } - virtual UpdateResult Update(TurnId turnId, int successorCount) override + virtual UpdateResult Update(TurnId turnId, size_t successorCount) override { if (! (this->Value() == slotInput_.dep->Value())) { @@ -272,7 +272,7 @@ class SignalSlotNode : public SignalNode virtual int GetDependencyCount() const override { return 0; } - virtual UpdateResult Update(TurnId turnId, int successorCount) override + virtual UpdateResult Update(TurnId turnId, size_t successorCount) override { if (dep != newDep) { @@ -328,7 +328,7 @@ class SignalLinkNode : public SignalNode virtual int GetDependencyCount() const override { return 1; } - virtual UpdateResult Update(TurnId turnId, int successorCount) override + virtual UpdateResult Update(TurnId turnId, size_t successorCount) override { return UpdateResult::changed; } @@ -363,7 +363,7 @@ class SignalLinkNode : public SignalNode virtual int GetDependencyCount() const override { return 1; } - virtual UpdateResult Update(TurnId turnId, int successorCount) override + virtual UpdateResult Update(TurnId turnId, size_t successorCount) override { return UpdateResult::changed; } From 933016dce85c34ff712529bf2cac94a180e08341 Mon Sep 17 00:00:00 2001 From: schlangster Date: Fri, 16 Dec 2016 18:04:21 +0100 Subject: [PATCH 40/75] wip stuff --- benchmarks/src/BenchmarkBase.h | 13 +- benchmarks/src/BenchmarkFanout.h | 7 +- benchmarks/src/BenchmarkGrid.h | 33 ++-- benchmarks/src/BenchmarkLifeSim.h | 10 +- benchmarks/src/BenchmarkRandom.h | 9 +- benchmarks/src/BenchmarkSequence.h | 7 +- benchmarks/src/Main.cpp | 52 +++--- examples/src/Main.cpp | 191 ++++++++++++++++++++- include/react/Signal.h | 41 +++-- include/react/detail/graph/PropagationST.h | 2 +- 10 files changed, 269 insertions(+), 96 deletions(-) diff --git a/benchmarks/src/BenchmarkBase.h b/benchmarks/src/BenchmarkBase.h index 528a8489..7df36bbe 100644 --- a/benchmarks/src/BenchmarkBase.h +++ b/benchmarks/src/BenchmarkBase.h @@ -66,9 +66,6 @@ template > void RunBenchmark(std::ostream& logfile, TBenchmark b, const TParams& params) { - std::cout << "Engine: " << typeid(typename TBenchmark::Domain::Policy::Engine).name() << std::endl << std::endl; - logfile << "Engine: " << typeid(typename TBenchmark::Domain::Policy::Engine).name() << std::endl << std::endl; - double sum = 0; double min = DBL_MAX; double max = DBL_MIN; @@ -77,7 +74,7 @@ void RunBenchmark(std::ostream& logfile, TBenchmark b, const TParams& params) { double r = b.Run(params); std::cout << "\tRun " << i << ": " << r << std::endl; - logfile << "\tRun " << i << ": " << r << std::endl; + logfile << "\tRun " << i << ": " << r << std::endl; sum += r; @@ -105,7 +102,7 @@ void RunBenchmark(std::ostream& logfile, TBenchmark b, const TParams& params) template < int RUN_COUNT, - template class TBenchmark, + typename TBenchmark, typename TParams > void RunBenchmarkClass(const char* name, std::ostream& out, const TParams& params) @@ -118,8 +115,8 @@ void RunBenchmarkClass(const char* name, std::ostream& out, const TParams& param params.Print(out); out << ") =====" << std::endl << std::endl; - REACT_EXPAND_PACK(RunBenchmark(out, TBenchmark(), params)); + RunBenchmark(out, TBenchmark(), params); } -#define RUN_BENCHMARK(out, runCount, benchmarkClass, params, ...) \ - RunBenchmarkClass(#benchmarkClass, out, params) +#define RUN_BENCHMARK(out, runCount, benchmarkClass, params) \ + RunBenchmarkClass(#benchmarkClass, out, params) diff --git a/benchmarks/src/BenchmarkFanout.h b/benchmarks/src/BenchmarkFanout.h index 6feaf567..672b5f7c 100644 --- a/benchmarks/src/BenchmarkFanout.h +++ b/benchmarks/src/BenchmarkFanout.h @@ -16,7 +16,7 @@ #include "BenchmarkBase.h" #include "react/Signal.h" - +/* using namespace react; /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -42,8 +42,7 @@ struct BenchmarkParams_Fanout const int Delay; }; -template -struct Benchmark_Fanout : public BenchmarkBase +struct Benchmark_Fanout { double Run(const BenchmarkParams_Fanout& params) { @@ -83,4 +82,6 @@ struct Benchmark_Fanout : public BenchmarkBase } }; +*/ + #endif // CPP_REACT_BENCHMARK_FANOUT_H \ No newline at end of file diff --git a/benchmarks/src/BenchmarkGrid.h b/benchmarks/src/BenchmarkGrid.h index 29afe312..6b691cc3 100644 --- a/benchmarks/src/BenchmarkGrid.h +++ b/benchmarks/src/BenchmarkGrid.h @@ -40,7 +40,7 @@ class GridGraphGenerator std::vector widths; - void Generate() + void Generate(const ReactiveGroupBase& group) { assert(inputSignals.size() >= 1); assert(widths.size() >= 1); @@ -48,8 +48,8 @@ class GridGraphGenerator SignalVectType buf1 = std::move(inputSignals); SignalVectType buf2; - SignalVectT* curBuf = &buf1; - SignalVectT* nextBuf = &buf2; + SignalVectType* curBuf = &buf1; + SignalVectType* nextBuf = &buf2; size_t curWidth = inputSignals.size(); @@ -70,36 +70,36 @@ class GridGraphGenerator if (shouldGrow) { - auto s = (*l) ->* Function1; - nextBuf->push_back(s); + auto s = SignalType{ group, function1, *l }; + nextBuf->push_back(std::move(s)); } while (r != curBuf->end()) { - auto s = (*l,*r) ->* Function2; - nextBuf->push_back(s); - nodeCount++; + auto s = SignalType{ group, function2, *l, *r }; + nextBuf->push_back(std::move(s)); + ++nodeCount; ++l; ++r; } if (shouldGrow) { - auto s = (*l) ->* Function1; - nextBuf->push_back(s); - nodeCount++; + auto s = SignalType{ group, function1, *l }; + nextBuf->push_back(std::move(s)); + ++nodeCount; } curBuf->clear(); // Swap buffer pointers - SignalVectT* t = curBuf; + SignalVectType* t = curBuf; curBuf = nextBuf; nextBuf = t; if (shouldGrow) - curWidth++; + ++curWidth; else - curWidth--; + --curWidth; } } @@ -135,10 +135,11 @@ struct Benchmark_Grid double Run(const BenchmarkParams_Grid& params, const ReactiveGroupBase& group) { VarSignal in{ group, 1 }; + Signal in2 = in; GridGraphGenerator generator; - generator.inputSignals.push_back(in); + generator.inputSignals.push_back(in2); generator.widths.push_back(params.N); generator.widths.push_back(1); @@ -146,7 +147,7 @@ struct Benchmark_Grid generator.function1 = [] (int a) { return a; }; generator.function2 = [] (int a, int b) { return a + b; }; - generator.Generate(); + generator.Generate(group); auto t0 = tbb::tick_count::now(); for (int i=0; i #include #include @@ -318,8 +318,10 @@ struct Benchmark_LifeSim : public BenchmarkBase logfile.open("log.txt"); D::Log().Write(logfile); - logfile.close()*/; + logfile.close()*//*; - return d; + //return d; } -}; \ No newline at end of file +}; + +*/ \ No newline at end of file diff --git a/benchmarks/src/BenchmarkRandom.h b/benchmarks/src/BenchmarkRandom.h index bf3ba9d1..e3ffe9ef 100644 --- a/benchmarks/src/BenchmarkRandom.h +++ b/benchmarks/src/BenchmarkRandom.h @@ -14,11 +14,11 @@ #include "BenchmarkBase.h" #include "react/common/Types.h" -#include "react/Domain.h" +#include "react/Group.h" #include "react/Signal.h" using namespace react; - +/* /////////////////////////////////////////////////////////////////////////////////////////////////// /// DiamondGraphGenerator /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -215,8 +215,7 @@ struct BenchmarkParams_Random const int SlowSeed; }; -template -struct Benchmark_Random : public BenchmarkBase +struct Benchmark_Random { double Run(const BenchmarkParams_Random& params) { @@ -321,4 +320,4 @@ struct Benchmark_Random : public BenchmarkBase return d; } -}; \ No newline at end of file +};*/ \ No newline at end of file diff --git a/benchmarks/src/BenchmarkSequence.h b/benchmarks/src/BenchmarkSequence.h index 5e96d3c7..bf87bc41 100644 --- a/benchmarks/src/BenchmarkSequence.h +++ b/benchmarks/src/BenchmarkSequence.h @@ -14,6 +14,8 @@ #include "react/Signal.h" +/* + using namespace react; /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -39,8 +41,7 @@ struct BenchmarkParams_Sequence const int Delay; }; -template -struct Benchmark_Sequence : public BenchmarkBase +struct Benchmark_Sequence { double Run(const BenchmarkParams_Sequence& params) { @@ -76,4 +77,4 @@ struct Benchmark_Sequence : public BenchmarkBase return d; } -}; \ No newline at end of file +};*/ \ No newline at end of file diff --git a/benchmarks/src/Main.cpp b/benchmarks/src/Main.cpp index cbf5aaca..2af96fdd 100644 --- a/benchmarks/src/Main.cpp +++ b/benchmarks/src/Main.cpp @@ -27,7 +27,7 @@ namespace { using namespace react; -void runBenchmarkGrid(std::ostream& out) +/*void runBenchmarkGrid(std::ostream& out) { RUN_BENCHMARK(out, 5, Benchmark_Grid, BenchmarkParams_Grid(20, 10000), ToposortSTDomain, ToposortDomain, PulsecountDomain); @@ -40,9 +40,9 @@ void runBenchmarkGrid(std::ostream& out) RUN_BENCHMARK(out, 5, Benchmark_Grid, BenchmarkParams_Grid(50, 10000), ToposortSTDomain, ToposortDomain, PulsecountDomain); -} +}*/ -void runBenchmarkRandom(std::ostream& out) +/*void runBenchmarkRandom(std::ostream& out) { const auto w = 20; const auto h = 11; @@ -67,7 +67,7 @@ void runBenchmarkRandom(std::ostream& out) seed1 *= 2; seed2 *= 2; } -} +}*/ void runBenchmarkFanout(std::ostream& out) { @@ -80,14 +80,14 @@ void runBenchmarkFanout(std::ostream& out) //RUN_BENCHMARK(out, 5, Benchmark_Fanout, BenchmarkParams_Fanout(1000, 10000, 0), // ToposortSTDomain, ToposortDomain, ELMDomain, PulsecountDomain, SourceSetDomain); - RUN_BENCHMARK(out, 3, Benchmark_Fanout, BenchmarkParams_Fanout(10, 10, 10), + /* RUN_BENCHMARK(out, 3, Benchmark_Fanout, BenchmarkParams_Fanout(10, 10, 10), ToposortSTDomain, ToposortDomain, PulsecountDomain); RUN_BENCHMARK(out, 3, Benchmark_Fanout, BenchmarkParams_Fanout(100, 10, 10), ToposortSTDomain, ToposortDomain, PulsecountDomain); RUN_BENCHMARK(out, 3, Benchmark_Fanout, BenchmarkParams_Fanout(1000, 10, 10), - ToposortSTDomain, ToposortDomain, PulsecountDomain); + ToposortSTDomain, ToposortDomain, PulsecountDomain);*/ } void runBenchmarkSequence(std::ostream& out) @@ -101,14 +101,14 @@ void runBenchmarkSequence(std::ostream& out) //RUN_BENCHMARK(out, 3, Benchmark_Sequence, BenchmarkParams_Sequence(1000, 10000, 0), // ToposortSTDomain, ToposortDomain, ELMDomain, PulsecountDomain, SourceSetDomain); - RUN_BENCHMARK(out, 3, Benchmark_Sequence, BenchmarkParams_Sequence(10, 10, 10), - ToposortSTDomain, ToposortDomain, PulsecountDomain); + //RUN_BENCHMARK(out, 3, Benchmark_Sequence, BenchmarkParams_Sequence(10, 10, 10), + // ToposortSTDomain, ToposortDomain, PulsecountDomain); - RUN_BENCHMARK(out, 3, Benchmark_Sequence, BenchmarkParams_Sequence(100, 10, 10), - ToposortSTDomain, ToposortDomain, PulsecountDomain); + //RUN_BENCHMARK(out, 3, Benchmark_Sequence, BenchmarkParams_Sequence(100, 10, 10), + // ToposortSTDomain, ToposortDomain, PulsecountDomain); - RUN_BENCHMARK(out, 3, Benchmark_Sequence, BenchmarkParams_Sequence(1000, 10, 10), - ToposortSTDomain, ToposortDomain, PulsecountDomain); + //RUN_BENCHMARK(out, 3, Benchmark_Sequence, BenchmarkParams_Sequence(1000, 10, 10), + // ToposortSTDomain, ToposortDomain, PulsecountDomain); } void runBenchmarkLifeSim(std::ostream& out) @@ -119,8 +119,8 @@ void runBenchmarkLifeSim(std::ostream& out) //RUN_BENCHMARK(std::cout, 1, Benchmark_LifeSim, BenchmarkParams_LifeSim(250, 30, 10000), // SourceSetDomain, PulsecountDomain); - RUN_BENCHMARK(out, 1, Benchmark_LifeSim, BenchmarkParams_LifeSim(100, 15, 10000), - ToposortSTDomainConc, ToposortDomainConc, PulsecountDomainConc); + //RUN_BENCHMARK(out, 1, Benchmark_LifeSim, BenchmarkParams_LifeSim(100, 15, 10000), + // ToposortSTDomainConc, ToposortDomainConc, PulsecountDomainConc); //RUN_BENCHMARK(out, 3, Benchmark_LifeSim, BenchmarkParams_LifeSim(100, 50, 100), // PulsecountDomain, PulsecountDomain); @@ -130,8 +130,8 @@ void runBenchmarks() { std::ofstream logfile; - std::string path = "Benchmark Results/" + CurrentDateTime() + ".txt"; - logfile.open(path.c_str()); + //std::string path = "Benchmark Results/" + CurrentDateTime() + ".txt"; + //logfile.open(path.c_str()); // === GRID //runBenchmarkGrid(logfile); @@ -148,14 +148,14 @@ void runBenchmarks() //runBenchmarkSequence(logfile); // === LIFESIM - runBenchmarkLifeSim(logfile); + //runBenchmarkLifeSim(logfile); logfile.close(); } void debugBenchmarks() { - using TestDomain = PulsecountDomain; + //using TestDomain = PulsecountDomain; //RUN_BENCHMARK(std::cout, 1, Benchmark_Grid, BenchmarkParams_Grid(30, 1), // TestDomain); @@ -172,8 +172,8 @@ void debugBenchmarks() //RUN_BENCHMARK(std::cout, 1, Benchmark_Random, BenchmarkParams_Random(10, 25, 10, 0, 10, 25, 25, false), // ToposortDomain); - RUN_BENCHMARK(std::cout, 1, Benchmark_Random, BenchmarkParams_Random(40, 11, 2, 0, 1, 40, 40, false, 41556, 21624), - TestDomain); + //RUN_BENCHMARK(std::cout, 1, Benchmark_Random, BenchmarkParams_Random(40, 11, 2, 0, 1, 40, 40, false, 41556, 21624), + // TestDomain); //const auto w = 10; //const auto h = 11; @@ -194,21 +194,11 @@ void debugBenchmarks() //RunBenchmark<1>(Benchmark2()); //RunBenchmark<1>(Benchmark2()); //RunBenchmark<3>(Benchmark2()); - -#ifdef REACT_ENABLE_LOGGING - std::ofstream logfile; - logfile.open("log.txt"); - - TestDomain::Log().Write(logfile); - logfile.close(); -#endif } void profileBenchmark() { - RUN_BENCHMARK(std::cout, 3, Benchmark_Grid, BenchmarkParams_Grid(100, 10000), - //SubtreeDomain); - ToposortSTDomain, ToposortDomain, PulsecountDomain, SubtreeDomain); + RUN_BENCHMARK(std::cout, 3, Benchmark_Grid, BenchmarkParams_Grid(100, 10000)); //RUN_BENCHMARK(std::cout, 1, Benchmark_Grid, BenchmarkParams_Grid(30, 10000), //SourceSetDomain); diff --git a/examples/src/Main.cpp b/examples/src/Main.cpp index e4fe6f5d..47a9494c 100644 --- a/examples/src/Main.cpp +++ b/examples/src/Main.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include "react/Signal.h" #include "react/Event.h" @@ -16,6 +17,97 @@ using namespace react; + +template +class GridGraphGenerator +{ +public: + using SignalType = Signal; + + using Func1T = std::function; + using Func2T = std::function; + + using SignalVectType = std::vector; + + SignalVectType inputSignals; + SignalVectType outputSignals; + + Func1T function1; + Func2T function2; + + std::vector widths; + + void Generate(const ReactiveGroupBase& group) + { + assert(inputSignals.size() >= 1); + assert(widths.size() >= 1); + + SignalVectType buf1 = std::move(inputSignals); + SignalVectType buf2; + + SignalVectType* curBuf = &buf1; + SignalVectType* nextBuf = &buf2; + + size_t curWidth = buf1.size(); + + size_t nodeCount = 1; + nodeCount += curWidth; + + for (auto targetWidth : widths) + { + while (curWidth != targetWidth) + { + // Grow or shrink? + bool shouldGrow = targetWidth > curWidth; + + auto l = curBuf->begin(); + auto r = curBuf->begin(); + if (r != curBuf->end()) + ++r; + + if (shouldGrow) + { + auto s = SignalType{ group, function1, *l }; + nextBuf->push_back(std::move(s)); + } + + while (r != curBuf->end()) + { + auto s = SignalType{ group, function2, *l, *r }; + nextBuf->push_back(std::move(s)); + ++nodeCount; + ++l; ++r; + } + + if (shouldGrow) + { + auto s = SignalType{ group, function1, *l }; + nextBuf->push_back(std::move(s)); + ++nodeCount; + } + + curBuf->clear(); + + // Swap buffer pointers + SignalVectType* t = curBuf; + curBuf = nextBuf; + nextBuf = t; + + if (shouldGrow) + ++curWidth; + else + --curWidth; + } + } + + //printf ("NODE COUNT %d\n", nodeCount); + + outputSignals.clear(); + outputSignals.insert(outputSignals.begin(), curBuf->begin(), curBuf->end()); + } +}; + + template T Multiply(T a, T b) { @@ -58,6 +150,16 @@ template bool FilterFunc(T v) return v > 10; } +template T IterFunc1(EventRange evts, T v) +{ + return v + 1; +} + +template T IterFunc2(EventRange evts, T v, T a1, T a2) +{ + return v + 1; +} + int main() { ReactiveGroup<> group; @@ -68,7 +170,7 @@ int main() VarSignal y{ group, 0 }; VarSignal z{ group, 0 }; - Signal area{ group, Multiply, x, y }; + Signal area{ Multiply, x, y }; Signal volume{ Multiply, area, z }; Observer<> areaObs{ PrintArea, area }; @@ -80,7 +182,7 @@ int main() group.DoTransaction([&] { - x <<= 100; + x.Set(100); y <<= 3; y <<= 4; }); @@ -124,6 +226,7 @@ int main() s2.Set(667); } + // Links { ReactiveGroup<> group1; ReactiveGroup<> group2; @@ -144,25 +247,68 @@ int main() ReactiveGroup<> group1; ReactiveGroup<> group2; - VarSignal s1{ group1, 10 }; + VarSignal s1{ group1, 10 }; + VarSignal s2{ group2, 11 }; + + EventSource e1{ group1 }; + EventSource e2{ group2 }; + + auto hold = Hold(group1, 0, e1); + + auto merged = Merge(group2, e1, e2); + + auto joined1 = Join(e1, e2); + auto joined2 = Join(group1, e1, e2); + + Observer<> eventObs1{ PrintEvents, merged }; + Observer<> eventObs2{ group2, PrintSyncedEvents, merged, s1, s2 }; + + e1.Emit(222); + + std::this_thread::sleep_for(std::chrono::seconds(5)); + } + + { + ReactiveGroup<> group1; + ReactiveGroup<> group2; + + VarSignal s1{ group1, 10 }; VarSignal s2{ group2, 11 }; EventSource e1{ group1 }; EventSource e2{ group2 }; - auto hold = Hold(group1, 0, e1); + auto hold1 = Hold(group1, 0, e1); + auto hold2 = Hold(0, e1); + + auto monitor1 = Monitor(group1, s1); + auto monitor2 = Monitor(s1); + + auto snapshot1 = Snapshot(group1, s1, e1); + auto snapshot2 = Snapshot(s1, e1); + + auto pulse1 = Pulse(group1, s1, e1); + auto pulse2 = Pulse(s1, e1); auto merged = Merge(group2, e1, e2); - auto joined = Join(e1, e2); + auto joined1 = Join(e1, e2); auto joined2 = Join(group1, e1, e2); + auto iter1 = Iterate(group, 0, IterFunc1, e1); + auto iter2 = Iterate(0, IterFunc1, e1); + + auto iter3 = Iterate(group, 0, IterFunc2, e1, s1, s2); + auto iter4 = Iterate(0, IterFunc2, e1, s1, s2); + Observer<> eventObs{ PrintEvents, merged }; - Observer<> eventObs2{ group2, PrintSyncedEvents, merged, s1, s2 }; + Observer<> eventObs2{ group2, PrintSyncedEvents, merged, s1, s2 }; e1.Emit(222); std::this_thread::sleep_for(std::chrono::seconds(5)); + + GridGraphGenerator grid; } return 0; @@ -178,7 +324,40 @@ int main() +int main() +{ + ReactiveGroup<> group; + + VarSignal in{ group, 1 }; + Signal in2 = in; + + GridGraphGenerator generator; + + generator.inputSignals.push_back(in2); + + generator.widths.push_back(100); + generator.widths.push_back(1); + + int updateCount = 0; + + generator.function1 = [&] (int a) { ++updateCount; return a; }; + generator.function2 = [&] (int a, int b) { ++updateCount; return a + b; }; + + generator.Generate(group); + + updateCount = 0; + auto t0 = tbb::tick_count::now(); + for (int i = 0; i < 10000; i++) + in <<= 10 + i; + auto t1 = tbb::tick_count::now(); + + double d = (t1 - t0).seconds(); + printf("updateCount %d\n", updateCount); + printf("Time %g\n", d); + + return 0; +} diff --git a/include/react/Signal.h b/include/react/Signal.h index bd5f62df..0bff5126 100644 --- a/include/react/Signal.h +++ b/include/react/Signal.h @@ -77,13 +77,6 @@ class SignalBase PrivateSignalLinkNodeInterface::GetLocalNodePtr(graphPtr, dep1), PrivateSignalLinkNodeInterface::GetLocalNodePtr(graphPtr, deps) ...); } - template - auto CreateFuncNode(F&& func, const SignalBase& dep1, const SignalBase& ... deps) -> decltype(auto) - { - using REACT_IMPL::PrivateNodeInterface; - return CreateFuncNode(PrivateNodeInterface::GraphPtr(dep1), std::forward(func), dep1, deps ...); - } - private: std::shared_ptr nodePtr_; @@ -266,16 +259,21 @@ class Signal : public SignalBase Signal(Signal&&) = default; Signal& operator=(Signal&&) = default; + // Construct from VarSignal + Signal(const VarSignalBase& other) : + Signal::SignalBase( other ) + { } + // Construct func signal with explicit group - template - explicit Signal(const ReactiveGroupBase& group, F&& func, const SignalBase& ... deps) : - Signal::SignalBase( REACT_IMPL::CtorTag{ }, CreateFuncNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), std::forward(func), deps ...) ) + template + explicit Signal(const ReactiveGroupBase& group, F&& func, const SignalBase& dep1, const SignalBase& ... deps) : + Signal::SignalBase( REACT_IMPL::CtorTag{ }, CreateFuncNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), std::forward(func), dep1, deps ...) ) { } // Construct func signal with implicit group - template - explicit Signal(F&& func, const SignalBase& ... deps) : - Signal::SignalBase( REACT_IMPL::CtorTag{ }, CreateFuncNode(std::forward(func), deps ...) ) + template + explicit Signal(F&& func, const SignalBase& dep1, const SignalBase& ... deps) : + Signal::SignalBase( REACT_IMPL::CtorTag{ }, CreateFuncNode(REACT_IMPL::PrivateNodeInterface::GraphPtr(dep1), std::forward(func), dep1, deps ...) ) { } }; @@ -295,6 +293,11 @@ class Signal : public SignalBase Signal(Signal&&) = default; Signal& operator=(Signal&&) = default; + // Construct from VarSignal + Signal(const VarSignalBase& other) : + Signal::SignalBase( other ) + { } + // Construct from unique Signal(Signal&& other) : Signal::SignalBase( std::move(other) ) @@ -305,15 +308,15 @@ class Signal : public SignalBase { Signal::SignalBase::operator=(std::move(other)); return *this; } // Construct func signal with explicit group - template - explicit Signal(const ReactiveGroupBase& group, F&& func, const SignalBase& ... deps) : - Signal::SignalBase( REACT_IMPL::CtorTag{ }, CreateFuncNode(std::forward(func), deps ...) ) + template + explicit Signal(const ReactiveGroupBase& group, F&& func, const SignalBase& dep1, const SignalBase& ... deps) : + Signal::SignalBase( REACT_IMPL::CtorTag{ }, CreateFuncNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), std::forward(func), dep1, deps ...) ) { } // Construct func signal with implicit group - template - explicit Signal(F&& func, const SignalBase& ... deps) : - Signal::SignalBase( REACT_IMPL::CtorTag{ }, CreateFuncNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), std::forward(func), deps ...) ) + template + explicit Signal(F&& func, const SignalBase& dep1, const SignalBase& ... deps) : + Signal::SignalBase( REACT_IMPL::CtorTag{ }, CreateFuncNode(REACT_IMPL::PrivateNodeInterface::GraphPtr(dep1), std::forward(func), dep1, deps ...) ) { } }; diff --git a/include/react/detail/graph/PropagationST.h b/include/react/detail/graph/PropagationST.h index dbce7777..814fc94c 100644 --- a/include/react/detail/graph/PropagationST.h +++ b/include/react/detail/graph/PropagationST.h @@ -216,7 +216,7 @@ void ReactiveGraph::AddInput(NodeId nodeId, F&& inputCallback) auto& node = nodeData_[nodeId]; auto* nodePtr = node.nodePtr; - // This write to the input buffer of the respective node. + // This writes to the input buffer of the respective node. inputCallback(); if (isTransactionActive_) From 2a802161125aea0eb0864aa54a04e3b0d12f07eb Mon Sep 17 00:00:00 2001 From: schlangster Date: Sun, 18 Dec 2016 13:45:36 +0100 Subject: [PATCH 41/75] refactor wip --- include/react/API.h | 65 ++---- include/react/Algorithm.h | 24 +-- include/react/Event.h | 360 +++++++++---------------------- include/react/Group.h | 58 +---- include/react/Signal.h | 442 +++++++++----------------------------- 5 files changed, 235 insertions(+), 714 deletions(-) diff --git a/include/react/API.h b/include/react/API.h index b1e86ad1..dbd0e5df 100644 --- a/include/react/API.h +++ b/include/react/API.h @@ -17,12 +17,6 @@ /////////////////////////////////////////////////////////////////////////////////////////////////// /// API constants /////////////////////////////////////////////////////////////////////////////////////////////////// -enum OwnershipPolicy -{ - unique, - shared -}; - enum class WeightHint { automatic, @@ -43,57 +37,34 @@ REACT_DEFINE_BITMASK_OPERATORS(TransactionFlags) /////////////////////////////////////////////////////////////////////////////////////////////////// // Groups -template class ReactiveGroup; // Signals template -class SignalBase; - -template -class VarSignalBase; - -template -class SignalSlotBase; - -template -class SignalLinkBase; - -template class Signal; -template +template class VarSignal; -template +template class SignalSlot; -template +template class SignalLink; // Events enum class Token; -template -class EventBase; - -template -class EventSourceBase; - -template -class EventSlotBase; - -template +template class Event; -template +template class EventSource; -template +template class EventSlot; // Observers -template class Observer; /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -102,29 +73,29 @@ class Observer; template struct IsSignal { static const bool value = false; }; -template -struct IsSignal> { static const bool value = true; }; +template +struct IsSignal> { static const bool value = true; }; -template -struct IsSignal> { static const bool value = true; }; +template +struct IsSignal> { static const bool value = true; }; template struct IsEvent { static const bool value = false; }; -template -struct IsEvent> { static const bool value = true; }; +template +struct IsEvent> { static const bool value = true; }; -template -struct IsEvent> { static const bool value = true; }; +template +struct IsEvent> { static const bool value = true; }; template struct AsNonInputNode { using type = T; }; -template -struct AsNonInputNode> { using type = Signal; }; +template +struct AsNonInputNode> { using type = Signal; }; -template -struct AsNonInputNode> { using type = Event; }; +template +struct AsNonInputNode> { using type = Event; }; /******************************************/ REACT_END /******************************************/ diff --git a/include/react/Algorithm.h b/include/react/Algorithm.h index 6a0037a2..b7e8324d 100644 --- a/include/react/Algorithm.h +++ b/include/react/Algorithm.h @@ -27,7 +27,7 @@ /// Hold - Hold the most recent event in a signal /////////////////////////////////////////////////////////////////////////////////////////////////// template -auto Hold(const ReactiveGroupBase& group, T&& initialValue, const EventBase& evnt) -> Signal +auto Hold(const ReactiveGroup& group, T&& initialValue, const Event& evnt) -> Signal { using REACT_IMPL::HoldNode; using REACT_IMPL::PrivateEventLinkNodeInterface; @@ -41,7 +41,7 @@ auto Hold(const ReactiveGroupBase& group, T&& initialValue, const EventBase& } template -auto Hold(T&& initialValue, const EventBase& evnt) -> Signal +auto Hold(T&& initialValue, const Event& evnt) -> Signal { using REACT_IMPL::HoldNode; using REACT_IMPL::PrivateEventLinkNodeInterface; @@ -58,7 +58,7 @@ auto Hold(T&& initialValue, const EventBase& evnt) -> Signal /// Monitor - Emits value changes of target signal /////////////////////////////////////////////////////////////////////////////////////////////////// template -auto Monitor(const ReactiveGroupBase& group, const SignalBase& signal) -> Event +auto Monitor(const ReactiveGroup& group, const Signal& signal) -> Event { using REACT_IMPL::MonitorNode; using REACT_IMPL::PrivateSignalLinkNodeInterface; @@ -72,7 +72,7 @@ auto Monitor(const ReactiveGroupBase& group, const SignalBase& signal) -> Eve } template -auto Monitor(const SignalBase& signal) -> Event +auto Monitor(const Signal& signal) -> Event { using REACT_IMPL::MonitorNode; using REACT_IMPL::PrivateSignalLinkNodeInterface; @@ -89,7 +89,7 @@ auto Monitor(const SignalBase& signal) -> Event /// Iterate - Iteratively combines signal value with values from event stream (aka Fold) /////////////////////////////////////////////////////////////////////////////////////////////////// template -auto Iterate(const ReactiveGroupBase& group, T&& initialValue, F&& func, const EventBase& evnt) -> Signal +auto Iterate(const ReactiveGroup& group, T&& initialValue, F&& func, const Event& evnt) -> Signal { using REACT_IMPL::IterateNode; using REACT_IMPL::IterateByRefNode; @@ -111,7 +111,7 @@ auto Iterate(const ReactiveGroupBase& group, T&& initialValue, F&& func, const E } template -auto Iterate(T&& initialValue, F&& func, const EventBase& evnt) -> Signal +auto Iterate(T&& initialValue, F&& func, const Event& evnt) -> Signal { using REACT_IMPL::IterateNode; using REACT_IMPL::IterateByRefNode; @@ -136,7 +136,7 @@ auto Iterate(T&& initialValue, F&& func, const EventBase& evnt) -> Signal -auto Iterate(const ReactiveGroupBase& group, T&& initialValue, F&& func, const EventBase& evnt, const SignalBase& ... signals) -> Signal +auto Iterate(const ReactiveGroup& group, T&& initialValue, F&& func, const Event& evnt, const Signal& ... signals) -> Signal { using REACT_IMPL::SyncedIterateNode; using REACT_IMPL::SyncedIterateByRefNode; @@ -160,7 +160,7 @@ auto Iterate(const ReactiveGroupBase& group, T&& initialValue, F&& func, const E } template -auto Iterate(T&& initialValue, F&& func, const EventBase& evnt, const SignalBase& ... signals) -> Signal +auto Iterate(T&& initialValue, F&& func, const Event& evnt, const Signal& ... signals) -> Signal { using REACT_IMPL::SyncedIterateNode; using REACT_IMPL::SyncedIterateByRefNode; @@ -187,7 +187,7 @@ auto Iterate(T&& initialValue, F&& func, const EventBase& evnt, const SignalB /// Snapshot - Sets signal value to value of other signal when event is received /////////////////////////////////////////////////////////////////////////////////////////////////// template -auto Snapshot(const ReactiveGroupBase& group, const SignalBase& signal, const EventBase& evnt) -> Signal +auto Snapshot(const ReactiveGroup& group, const Signal& signal, const Event& evnt) -> Signal { using REACT_IMPL::SnapshotNode; using REACT_IMPL::PrivateSignalLinkNodeInterface; @@ -202,7 +202,7 @@ auto Snapshot(const ReactiveGroupBase& group, const SignalBase& signal, const } template -auto Snapshot(const SignalBase& signal, const EventBase& evnt) -> Signal +auto Snapshot(const Signal& signal, const Event& evnt) -> Signal { using REACT_IMPL::SnapshotNode; using REACT_IMPL::PrivateSignalLinkNodeInterface; @@ -220,7 +220,7 @@ auto Snapshot(const SignalBase& signal, const EventBase& evnt) -> Signal -auto Pulse(const ReactiveGroupBase& group, const SignalBase& signal, const EventBase& evnt) -> Event +auto Pulse(const ReactiveGroup& group, const Signal& signal, const Event& evnt) -> Event { using REACT_IMPL::PulseNode; using REACT_IMPL::PrivateSignalLinkNodeInterface; @@ -235,7 +235,7 @@ auto Pulse(const ReactiveGroupBase& group, const SignalBase& signal, const Ev } template -auto Pulse(const SignalBase& signal, const EventBase& evnt) -> Event +auto Pulse(const Signal& signal, const Event& evnt) -> Event { using REACT_IMPL::PulseNode; using REACT_IMPL::PrivateSignalLinkNodeInterface; diff --git a/include/react/Event.h b/include/react/Event.h index bf8c0a05..da63eb35 100644 --- a/include/react/Event.h +++ b/include/react/Event.h @@ -28,18 +28,41 @@ struct PrivateEventLinkNodeInterface; /*****************************************/ REACT_BEGIN /*****************************************/ /////////////////////////////////////////////////////////////////////////////////////////////////// -/// Events +/// Event /////////////////////////////////////////////////////////////////////////////////////////////////// -template -class EventBase +template +class Event { private: using NodeType = REACT_IMPL::EventStreamNode; public: - // Private node ctor - EventBase(REACT_IMPL::CtorTag, std::shared_ptr&& nodePtr) : - nodePtr_( std::move(nodePtr) ) + Event() = default; + + Event(const Event&) = default; + Event& operator=(const Event&) = default; + + Event(Event&&) = default; + Event& operator=(Event&&) = default; + + template + Event(F&& func, const Event& dep) : + Event::Event( REACT_IMPL::CtorTag{ }, CreateProcessingNode(std::forward(func), dep) ) + { } + + template + Event(const ReactiveGroup& group, F&& func, const Event& dep) : + Event::Event( REACT_IMPL::CtorTag{ }, CreateProcessingNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), std::forward(func), dep) ) + { } + + template + Event(F&& func, const Event& dep, const Signal& ... signals) : + Event::Event( REACT_IMPL::CtorTag{ }, CreateSyncedProcessingNode(std::forward(func), dep, signals ...) ) + { } + + template + Event(const ReactiveGroup& group, F&& func, const Event& dep, const Signal& ... signals) : + Event::Event( REACT_IMPL::CtorTag{ }, CreateSyncedProcessingNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), std::forward(func), dep, signals ...) ) { } auto Tokenize() const -> decltype(auto) @@ -58,13 +81,10 @@ class EventBase { return REACT::Transform(*this, std::forward(f)); }*/ protected: - EventBase() = default; - - EventBase(const EventBase&) = default; - EventBase& operator=(const EventBase&) = default; - - EventBase(EventBase&&) = default; - EventBase& operator=(EventBase&&) = default; + // Internal node ctor + Event(REACT_IMPL::CtorTag, std::shared_ptr&& nodePtr) : + nodePtr_( std::move(nodePtr) ) + { } auto NodePtr() -> std::shared_ptr& { return nodePtr_; } @@ -73,7 +93,7 @@ class EventBase { return nodePtr_; } template - auto CreateProcessingNode(F&& func, const EventBase& dep) -> decltype(auto) + auto CreateProcessingNode(F&& func, const Event& dep) -> decltype(auto) { using REACT_IMPL::PrivateNodeInterface; using EventNodeType = REACT_IMPL::EventProcessingNode::type>; @@ -82,7 +102,7 @@ class EventBase } template - auto CreateSyncedProcessingNode(F&& func, const EventBase& dep, const SignalBase& ... syncs) -> decltype(auto) + auto CreateSyncedProcessingNode(F&& func, const Event& dep, const Signal& ... syncs) -> decltype(auto) { using REACT_IMPL::GetCheckedGraphPtr; using REACT_IMPL::PrivateNodeInterface; @@ -103,11 +123,22 @@ class EventBase /////////////////////////////////////////////////////////////////////////////////////////////////// /// EventSource /////////////////////////////////////////////////////////////////////////////////////////////////// -template -class EventSourceBase : public EventBase +template +class EventSource : public Event { public: - using EventBase::EventBase; + EventSource() = default; + + EventSource(const EventSource&) = default; + EventSource& operator=(const EventSource&) = default; + + EventSource(EventSource&& other) = default; + EventSource& operator=(EventSource&& other) = default; + + // Construct event source + explicit EventSource(const ReactiveGroup& group) : + EventSource::Event( REACT_IMPL::CtorTag{ }, CreateSourceNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group)) ) + { } void Emit(const E& value) { EmitValue(value); } @@ -119,20 +150,14 @@ class EventSourceBase : public EventBase void Emit() { EmitValue(Token::value); } - EventSourceBase& operator<<(const E& value) + EventSource& operator<<(const E& value) { EmitValue(e); return *this; } - EventSourceBase& operator<<(E&& value) + EventSource& operator<<(E&& value) { EmitValue(std::move(value)); return *this; } protected: - EventSourceBase() = default; - - EventSourceBase(const EventSourceBase&) = default; - EventSourceBase& operator=(const EventSourceBase&) = default; - EventSourceBase(EventSourceBase&& other) = default; - EventSourceBase& operator=(EventSourceBase&& other) = default; auto CreateSourceNode(const std::shared_ptr& graphPtr) -> decltype(auto) { @@ -160,27 +185,30 @@ class EventSourceBase : public EventBase /// EventSlotBase /////////////////////////////////////////////////////////////////////////////////////////////////// template -class EventSlotBase : public EventBase +class EventSlot : public Event { public: - using EventBase::EventBase; + EventSlot() = default; - void Set(const EventBase& newInput) - { SetInput(newInput); } + EventSlot(const EventSlot&) = default; + EventSlot& operator=(const EventSlot&) = default; - void operator<<=(const EventBase& newInput) - { SetInput(newInput); } + EventSlot(EventSlot&&) = default; + EventSlot& operator=(EventSlot&&) = default; -protected: - EventSlotBase() = default; + // Construct with value + EventSlot(const ReactiveGroup& group, const Event& input) : + EventSlot::EventSlotBase( REACT_IMPL::CtorTag{ }, CreateSlotNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), input) ) + { } - EventSlotBase(const EventSlotBase&) = default; - EventSlotBase& operator=(const EventSlotBase&) = default; + void Set(const Event& newInput) + { SetInput(newInput); } - EventSlotBase(EventSlotBase&&) = default; - EventSlotBase& operator=(EventSlotBase&&) = default; + void operator<<=(const Event& newInput) + { SetInput(newInput); } - auto CreateSlotNode(const std::shared_ptr& graphPtr, const EventBase& input) -> decltype(auto) +protected: + auto CreateSlotNode(const std::shared_ptr& graphPtr, const Event& input) -> decltype(auto) { using REACT_IMPL::PrivateNodeInterface; using REACT_IMPL::PrivateReactiveGroupInterface; @@ -190,7 +218,7 @@ class EventSlotBase : public EventBase } private: - void SetInput(const EventBase& newInput) + void SetInput(const Event& newInput) { using REACT_IMPL::PrivateNodeInterface; using REACT_IMPL::NodeId; @@ -206,24 +234,32 @@ class EventSlotBase : public EventBase }; /////////////////////////////////////////////////////////////////////////////////////////////////// -/// EventLinkBase +/// EventLink /////////////////////////////////////////////////////////////////////////////////////////////////// template -class EventLinkBase : public EventBase +class EventLink : public Event { public: - using EventBase::EventBase; + EventLink() = default; -protected: - EventLinkBase() = default; + EventLink(const EventLink&) = default; + EventLink& operator=(const EventLink&) = default; - EventLinkBase(const EventLinkBase&) = default; - EventLinkBase& operator=(const EventLinkBase&) = default; + EventLink(EventLink&&) = default; + EventLink& operator=(EventLink&&) = default; - EventLinkBase(EventLinkBase&&) = default; - EventLinkBase& operator=(EventLinkBase&&) = default; + // Construct with explicit group + EventLink(const ReactiveGroup& group, const Event& input) : + SignalLink::Signal( REACT_IMPL::CtorTag{ }, CreateLinkNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), input) ) + { } + + // Construct with implicit group + explicit EventLink(const Event& input) : + SignalLink::Signal( REACT_IMPL::CtorTag{ }, CreateLinkNode(REACT_IMPL::PrivateNodeInterface::GraphPtr(input), input) ) + { } - static auto CreateLinkNode(const std::shared_ptr& graphPtr, const EventBase& input) -> decltype(auto) +protected: + static auto CreateLinkNode(const std::shared_ptr& graphPtr, const Event& input) -> decltype(auto) { using REACT_IMPL::PrivateNodeInterface; using REACT_IMPL::PrivateReactiveGroupInterface; @@ -237,207 +273,11 @@ class EventLinkBase : public EventBase friend struct REACT_IMPL::PrivateEventLinkNodeInterface; }; -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Event -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -class Event : public EventBase -{ -public: - using EventBase::EventBase; - - using ValueType = E; - - Event() = delete; - - Event(const Event&) = delete; - Event& operator=(const Event&) = delete; - - Event(Event&&) = default; - Event& operator=(Event&&) = default; - - template - Event(F&& func, const EventBase& dep) : - Event::EventBase( REACT_IMPL::CtorTag{ }, CreateProcessingNode(std::forward(func), dep) ) - { } - - template - Event(const ReactiveGroupBase& group, F&& func, const EventBase& dep) : - Event::EventBase( REACT_IMPL::CtorTag{ }, CreateProcessingNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), std::forward(func), dep) ) - { } - - template - Event(F&& func, const EventBase& dep, const SignalBase& ... signals) : - Event::EventBase( REACT_IMPL::CtorTag{ }, CreateSyncedProcessingNode(std::forward(func), dep, signals ...) ) - { } - - template - Event(const ReactiveGroupBase& group, F&& func, const EventBase& dep, const SignalBase& ... signals) : - Event::EventBase( REACT_IMPL::CtorTag{ }, CreateSyncedProcessingNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), std::forward(func), dep, signals ...) ) - { } -}; - -template -class Event : public EventBase -{ -public: - using EventBase::EventBase; - - using ValueType = E; - - Event() = delete; - - Event(const Event&) = default; - Event& operator=(const Event&) = default; - - Event(Event&&) = default; - Event& operator=(Event&&) = default; - - Event(Event&& other) : - Event::EventBase( std::move(other) ) - { } - - Event& operator=(Event&& other) - { Event::EventBase::operator=(std::move(other)); return *this; } - - template - Event(F&& func, const EventBase& dep) : - Event::EventBase( REACT_IMPL::CtorTag{ }, CreateProcessingNode(std::forward(func), dep) ) - { } - - template - Event(const ReactiveGroupBase& group, F&& func, const EventBase& dep) : - Event::EventBase( REACT_IMPL::CtorTag{ }, CreateProcessingNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), std::forward(func), dep) ) - { } - - template - Event(F&& func, const EventBase& dep, const SignalBase& ... signals) : - Event::EventBase( REACT_IMPL::CtorTag{ }, CreateSyncedProcessingNode(std::forward(func), dep, signals ...) ) - { } - - template - Event(const ReactiveGroupBase& group, F&& func, const EventBase& dep, const SignalBase& ... signals) : - Event::EventBase( REACT_IMPL::CtorTag{ }, CreateSyncedProcessingNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), std::forward(func), dep, signals ...) ) - { } -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// EventSource -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -class EventSource : public EventSourceBase -{ -public: - using EventSourceBase::EventSourceBase; - - using ValueType = E; - - EventSource() = delete; - - EventSource(const EventSource&) = delete; - EventSource& operator=(const EventSource&) = delete; - - EventSource(EventSource&&) = default; - EventSource& operator=(EventSource&&) = default; - - // Construct event source - explicit EventSource(const ReactiveGroupBase& group) : - EventSource::EventSourceBase( REACT_IMPL::CtorTag{ }, CreateSourceNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group)) ) - { } -}; - -template -class EventSource : public EventSourceBase -{ -public: - using EventSourceBase::EventSourceBase; - - using ValueType = E; - - EventSource() = delete; - - EventSource(const EventSource&) = default; - EventSource& operator=(const EventSource&) = default; - - EventSource(EventSource&&) = default; - EventSource& operator=(EventSource&&) = default; - - // Construct event source - explicit EventSource(const ReactiveGroupBase& group) : - EventSource::EventSourceBase( REACT_IMPL::CtorTag{ }, CreateSourceNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group)) ) - { } - - // Construct from unique - EventSource(EventSource&& other) : - EventSource::EventSourceBase( std::move(other) ) - { } - - // Assign from unique - EventSource& operator=(EventSource&& other) - { EventSource::EventSourceBase::operator=(std::move(other)); return *this; } -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// EventSlot -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -class EventSlot : public EventSlotBase -{ -public: - using EventSlotBase::EventSlotBase; - - using ValueType = E; - - EventSlot() = delete; - - EventSlot(const EventSlot&) = delete; - EventSlot& operator=(const EventSlot&) = delete; - - EventSlot(EventSlot&&) = default; - EventSlot& operator=(EventSlot&&) = default; - - // Construct with value - EventSlot(const ReactiveGroupBase& group, const EventBase& input) : - EventSlot::EventSlotBase( REACT_IMPL::CtorTag{ }, CreateSlotNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), input) ) - { } -}; - -template -class EventSlot : public EventSlotBase -{ -public: - using EventSlotBase::EventSlotBase; - - using ValueType = E; - - EventSlot() = delete; - - EventSlot(const EventSlot&) = default; - EventSlot& operator=(const EventSlot&) = default; - - EventSlot(EventSlot&&) = default; - EventSlot& operator=(EventSlot&&) = default; - - // Construct from unique - EventSlot(EventSlot&& other) : - EventSlot::EventSlotBase( std::move(other) ) - { } - - // Assign from unique - EventSlot& operator=(EventSlot&& other) - { EventSlot::EventSlotBase::operator=(std::move(other)); return *this; } - - // Construct with value - EventSlot(const ReactiveGroupBase& group, const SignalBase& input) : - EventSlot::EventSlotBase( REACT_IMPL::CtorTag{ }, CreateSlotNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), input) ) - { } -}; - /////////////////////////////////////////////////////////////////////////////////////////////////// /// Merge /////////////////////////////////////////////////////////////////////////////////////////////////// template -auto Merge(const ReactiveGroupBase& group, const EventBase& dep1, const EventBase& ... deps) -> decltype(auto) +auto Merge(const ReactiveGroup& group, const Event& dep1, const Event& ... deps) -> decltype(auto) { using REACT_IMPL::EventMergeNode; using REACT_IMPL::PrivateEventLinkNodeInterface; @@ -459,7 +299,7 @@ auto Merge(const ReactiveGroupBase& group, const EventBase& dep1, const Even } template -auto Merge(const EventBase& dep1, const EventBase& ... deps) -> decltype(auto) +auto Merge(const Event& dep1, const Event& ... deps) -> decltype(auto) { using REACT_IMPL::EventMergeNode; using REACT_IMPL::PrivateEventLinkNodeInterface; @@ -484,7 +324,7 @@ auto Merge(const EventBase& dep1, const EventBase& ... deps) -> decltype /// Filter /////////////////////////////////////////////////////////////////////////////////////////////////// template -auto Filter(const ReactiveGroupBase& group, F&& pred, const EventBase& dep) -> Event +auto Filter(const ReactiveGroup& group, F&& pred, const Event& dep) -> Event { auto filterFunc = [capturedPred = std::forward(pred)] (EventRange inRange, EventSink out) { std::copy_if(inRange.begin(), inRange.end(), out, capturedPred); }; @@ -493,7 +333,7 @@ auto Filter(const ReactiveGroupBase& group, F&& pred, const EventBase& dep) - } template -auto Filter(F&& pred, const EventBase& dep) -> Event +auto Filter(F&& pred, const Event& dep) -> Event { auto filterFunc = [capturedPred = std::forward(pred)] (EventRange inRange, EventSink out) { std::copy_if(inRange.begin(), inRange.end(), out, capturedPred); }; @@ -502,7 +342,7 @@ auto Filter(F&& pred, const EventBase& dep) -> Event } template -auto Filter(const ReactiveGroupBase& group, F&& pred, const EventBase& dep, const SignalBase& ... signals) -> Event +auto Filter(const ReactiveGroup& group, F&& pred, const Event& dep, const Signal& ... signals) -> Event { auto filterFunc = [capturedPred = std::forward(pred)] (EventRange inRange, EventSink out, const Us& ... values) { @@ -515,7 +355,7 @@ auto Filter(const ReactiveGroupBase& group, F&& pred, const EventBase& dep, c } template -auto Filter(F&& pred, const EventBase& dep, const SignalBase& ... signals) -> Event +auto Filter(F&& pred, const Event& dep, const Signal& ... signals) -> Event { auto filterFunc = [capturedPred = std::forward(pred)] (EventRange inRange, EventSink out, const Us& ... values) { @@ -531,7 +371,7 @@ auto Filter(F&& pred, const EventBase& dep, const SignalBase& ... signals /// Transform /////////////////////////////////////////////////////////////////////////////////////////////////// template -auto Transform(const ReactiveGroupBase& group, F&& op, const EventBase& dep) -> Event +auto Transform(const ReactiveGroup& group, F&& op, const Event& dep) -> Event { auto transformFunc = [capturedOp = std::forward(op)] (EventRange inRange, EventSink out) { std::transform(inRange.begin(), inRange.end(), out, capturedOp); }; @@ -540,7 +380,7 @@ auto Transform(const ReactiveGroupBase& group, F&& op, const EventBase& dep) } template -auto Transform(F&& op, const EventBase& dep) -> Event +auto Transform(F&& op, const Event& dep) -> Event { auto transformFunc = [capturedOp = std::forward(op)] (EventRange inRange, EventSink out) { std::transform(inRange.begin(), inRange.end(), out, capturedOp); }; @@ -549,7 +389,7 @@ auto Transform(F&& op, const EventBase& dep) -> Event } template -auto Transform(const ReactiveGroupBase& group, F&& op, const EventBase& dep, const SignalBase& ... signals) -> Event +auto Transform(const ReactiveGroup& group, F&& op, const Event& dep, const Signal& ... signals) -> Event { auto transformFunc = [capturedOp = std::forward(pred)] (EventRange inRange, EventSink out, const Vs& ... values) { @@ -561,7 +401,7 @@ auto Transform(const ReactiveGroupBase& group, F&& op, const EventBase& dep, } template -auto Transform(F&& op, const EventBase& dep, const SignalBase& ... signals) -> Event +auto Transform(F&& op, const Event& dep, const Signal& ... signals) -> Event { auto transformFunc = [capturedOp = std::forward(pred)] (EventRange inRange, EventSink out, const Vs& ... values) { @@ -587,7 +427,7 @@ auto Flatten(const Signal>& outer) -> Events /// Join /////////////////////////////////////////////////////////////////////////////////////////////////// template -auto Join(const ReactiveGroupBase& group, const EventBase& dep1, const EventBase& ... deps) -> Event, unique> +auto Join(const ReactiveGroup& group, const Event& dep1, const Event& ... deps) -> Event> { using REACT_IMPL::EventJoinNode; using REACT_IMPL::PrivateReactiveGroupInterface; @@ -604,7 +444,7 @@ auto Join(const ReactiveGroupBase& group, const EventBase& dep1, const Event } template -auto Join(const EventBase& dep1, const EventBase& ... deps) -> Event, unique> +auto Join(const Event& dep1, const Event& ... deps) -> Event> { using REACT_IMPL::EventJoinNode; using REACT_IMPL::PrivateNodeInterface; @@ -642,7 +482,7 @@ auto Tokenize(T&& source) -> decltype(auto) /***************************************/ REACT_IMPL_BEGIN /**************************************/ template -bool Equals(const EventBase& lhs, const EventBase& rhs) +bool Equals(const Event& lhs, const Event& rhs) { return lhs.Equals(rhs); } @@ -650,7 +490,7 @@ bool Equals(const EventBase& lhs, const EventBase& rhs) struct PrivateEventLinkNodeInterface { template - static auto GetLocalNodePtr(const std::shared_ptr& targetGraph, const EventBase& dep) -> std::shared_ptr> + static auto GetLocalNodePtr(const std::shared_ptr& targetGraph, const Event& dep) -> std::shared_ptr> { const std::shared_ptr& sourceGraph = PrivateNodeInterface::GraphPtr(dep); diff --git a/include/react/Group.h b/include/react/Group.h index ca2c02f0..837a2189 100644 --- a/include/react/Group.h +++ b/include/react/Group.h @@ -87,16 +87,20 @@ class TransactionStatus /////////////////////////////////////////////////////////////////////////////////////////////////// /// ReactiveGroupBase /////////////////////////////////////////////////////////////////////////////////////////////////// -class ReactiveGroupBase +class ReactiveGroup { using GraphType = REACT_IMPL::ReactiveGraph; public: - ReactiveGroupBase() : + ReactiveGroup() : graphPtr_( std::make_shared() ) { } - ~ReactiveGroupBase() = default; + ReactiveGroup(const ReactiveGroup&) = default; + ReactiveGroup& operator=(const ReactiveGroup&) = default; + + ReactiveGroup(ReactiveGroup&& other) = default; + ReactiveGroup& operator=(ReactiveGroup&& other) = default; template void DoTransaction(F&& func) @@ -111,12 +115,6 @@ class ReactiveGroupBase { graphPtr_->EnqueueTransaction(flags, std::forward(func)); } protected: - ReactiveGroupBase(const ReactiveGroupBase&) = default; - ReactiveGroupBase& operator=(const ReactiveGroupBase&) = default; - - ReactiveGroupBase(ReactiveGroupBase&& other) = default; - ReactiveGroupBase& operator=(ReactiveGroupBase&& other) = default; - auto GraphPtr() -> std::shared_ptr& { return graphPtr_; } @@ -129,44 +127,6 @@ class ReactiveGroupBase friend struct REACT_IMPL::PrivateReactiveGroupInterface; }; -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Signal -/////////////////////////////////////////////////////////////////////////////////////////////////// -template <> -class ReactiveGroup : public ReactiveGroupBase -{ -public: - ReactiveGroup() = default; - - ReactiveGroup(const ReactiveGroup&) = delete; - ReactiveGroup& operator=(const ReactiveGroup&) = delete; - - ReactiveGroup(ReactiveGroup&& other) = default; - ReactiveGroup& operator=(ReactiveGroup&& other) = default; -}; - -template <> -class ReactiveGroup : public ReactiveGroupBase -{ -public: - ReactiveGroup() = default; - - ReactiveGroup(const ReactiveGroup&) = default; - ReactiveGroup& operator=(const ReactiveGroup&) = default; - - ReactiveGroup(ReactiveGroup&& other) = default; - ReactiveGroup& operator=(ReactiveGroup&& other) = default; - - // Construct from unique - ReactiveGroup(ReactiveGroup&& other) : - ReactiveGroup::ReactiveGroupBase( std::move(other) ) - { } - - // Assign from unique - ReactiveGroup& operator=(ReactiveGroup&& other) - { ReactiveGroup::ReactiveGroupBase::operator=(std::move(other)); return *this; } -}; - /******************************************/ REACT_END /******************************************/ /***************************************/ REACT_IMPL_BEGIN /**************************************/ @@ -192,10 +152,10 @@ struct PrivateNodeInterface struct PrivateReactiveGroupInterface { - static auto GraphPtr(const ReactiveGroupBase& group) -> const std::shared_ptr& + static auto GraphPtr(const ReactiveGroup& group) -> const std::shared_ptr& { return group.GraphPtr(); } - static auto GraphPtr(ReactiveGroupBase& group) -> std::shared_ptr& + static auto GraphPtr(ReactiveGroup& group) -> std::shared_ptr& { return group.GraphPtr(); } }; diff --git a/include/react/Signal.h b/include/react/Signal.h index 0bff5126..786710d3 100644 --- a/include/react/Signal.h +++ b/include/react/Signal.h @@ -33,31 +33,46 @@ struct PrivateSignalLinkNodeInterface; /*****************************************/ REACT_BEGIN /*****************************************/ /////////////////////////////////////////////////////////////////////////////////////////////////// -/// SignalBase +/// Signal /////////////////////////////////////////////////////////////////////////////////////////////////// template -class SignalBase +class Signal { private: using NodeType = REACT_IMPL::SignalNode; public: - // Private node ctor - SignalBase(REACT_IMPL::CtorTag, std::shared_ptr&& nodePtr) : - nodePtr_( std::move(nodePtr) ) - { } - const S& Value() const { return nodePtr_->Value(); } -protected: - SignalBase() = default; + // Empty signal + Signal() = default; - SignalBase(const SignalBase&) = default; - SignalBase& operator=(const SignalBase&) = default; + // Copy ctor & assignment + Signal(const Signal&) = default; + Signal& operator=(const Signal&) = default; - SignalBase(SignalBase&&) = default; - SignalBase& operator=(SignalBase&&) = default; + // Move ctor & assignment + Signal(Signal&&) = default; + Signal& operator=(Signal&&) = default; + + // Construct func signal with explicit group + template + explicit Signal(const ReactiveGroup& group, F&& func, const Signal& dep1, const Signal& ... deps) : + Signal::Signal( REACT_IMPL::CtorTag{ }, CreateFuncNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), std::forward(func), dep1, deps ...) ) + { } + + // Construct func signal with implicit group + template + explicit Signal(F&& func, const Signal& dep1, const Signal& ... deps) : + Signal::Signal( REACT_IMPL::CtorTag{ }, CreateFuncNode(REACT_IMPL::PrivateNodeInterface::GraphPtr(dep1), std::forward(func), dep1, deps ...) ) + { } + +protected: + // Private node ctor + Signal(REACT_IMPL::CtorTag, std::shared_ptr&& nodePtr) : + nodePtr_( std::move(nodePtr) ) + { } auto NodePtr() -> std::shared_ptr& { return nodePtr_; } @@ -66,7 +81,7 @@ class SignalBase { return nodePtr_; } template - auto CreateFuncNode(const std::shared_ptr& graphPtr, F&& func, const SignalBase& dep1, const SignalBase& ... deps) -> decltype(auto) + auto CreateFuncNode(const std::shared_ptr& graphPtr, F&& func, const Signal& dep1, const Signal& ... deps) -> decltype(auto) { using REACT_IMPL::PrivateSignalLinkNodeInterface; using FuncNodeType = REACT_IMPL::SignalFuncNode::type, T1, Ts ...>; @@ -85,13 +100,32 @@ class SignalBase /////////////////////////////////////////////////////////////////////////////////////////////////// -/// VarSignalBase +/// VarSignal /////////////////////////////////////////////////////////////////////////////////////////////////// template -class VarSignalBase : public SignalBase +class VarSignal : public Signal { public: - using SignalBase::SignalBase; + using Signal::Signal; + + VarSignal() = default; + + VarSignal(const VarSignal&) = default; + VarSignal& operator=(const VarSignal&) = default; + + VarSignal(VarSignal&&) = default; + VarSignal& operator=(VarSignal&&) = default; + + // Construct with group + default + explicit VarSignal(const ReactiveGroup& group) : + VarSignal::Signal( REACT_IMPL::CtorTag{ }, CreateVarNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group)) ) + { } + + // Construct with group + value + template + VarSignal(const ReactiveGroup& group, T&& value) : + VarSignal::Signal( REACT_IMPL::CtorTag{ }, CreateVarNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), std::forward(value)) ) + { } void Set(const S& newValue) { SetValue(newValue); } @@ -110,14 +144,6 @@ class VarSignalBase : public SignalBase { ModifyValue(func); } protected: - VarSignalBase() = default; - - VarSignalBase(const VarSignalBase&) = default; - VarSignalBase& operator=(const VarSignalBase&) = default; - - VarSignalBase(VarSignalBase&&) = default; - VarSignalBase& operator=(VarSignalBase&&) = default; - static auto CreateVarNode(const std::shared_ptr& graphPtr) -> decltype(auto) { using VarNodeType = REACT_IMPL::VarSignalNode; @@ -165,27 +191,38 @@ class VarSignalBase : public SignalBase /// SignalSlotBase /////////////////////////////////////////////////////////////////////////////////////////////////// template -class SignalSlotBase : public SignalBase +class SignalSlot : public Signal { public: - using SignalBase::SignalBase; + SignalSlot(const SignalSlot&) = default; + SignalSlot& operator=(const SignalSlot&) = default; - void Set(const SignalBase& newInput) - { SetInput(newInput); } + SignalSlot(SignalSlot&&) = default; + SignalSlot& operator=(SignalSlot&&) = default; - void operator<<=(const SignalBase& newInput) - { SetInput(newInput); } + // Construct with group + default + explicit SignalSlot(const ReactiveGroup& group) : + SignalSlot::SignalSlotBase( REACT_IMPL::CtorTag{ }, CreateSlotNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group)) ) + { } -protected: - SignalSlotBase() = default; + // Construct with group + value + SignalSlot(const ReactiveGroup& group, const Signal& input) : + SignalSlot::SignalSlotBase( REACT_IMPL::CtorTag{ }, CreateSlotNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), input) ) + { } + + // Construct with value + explicit SignalSlot(const Signal& input) : + SignalSlot::SignalSlotBase( REACT_IMPL::CtorTag{ }, CreateSlotNode(REACT_IMPL::PrivateNodeInterface::GraphPtr(input), input) ) + { } - SignalSlotBase(const SignalSlotBase&) = default; - SignalSlotBase& operator=(const SignalSlotBase&) = default; + void Set(const Signal& newInput) + { SetInput(newInput); } - SignalSlotBase(SignalSlotBase&&) = default; - SignalSlotBase& operator=(SignalSlotBase&&) = default; + void operator<<=(const Signal& newInput) + { SetInput(newInput); } - static auto CreateSlotNode(const std::shared_ptr& graphPtr, const SignalBase& input) -> decltype(auto) +protected: + static auto CreateSlotNode(const std::shared_ptr& graphPtr, const Signal& input) -> decltype(auto) { using REACT_IMPL::PrivateNodeInterface; using SlotNodeType = REACT_IMPL::SignalSlotNode; @@ -194,7 +231,7 @@ class SignalSlotBase : public SignalBase } private: - void SetInput(const SignalBase& newInput) + void SetInput(const Signal& newInput) { using REACT_IMPL::PrivateNodeInterface; using REACT_IMPL::NodeId; @@ -209,24 +246,32 @@ class SignalSlotBase : public SignalBase }; /////////////////////////////////////////////////////////////////////////////////////////////////// -/// SignalLinkBase +/// SignalLink /////////////////////////////////////////////////////////////////////////////////////////////////// template -class SignalLinkBase : public SignalBase +class SignalLink : public Signal { public: - using SignalBase::SignalBase; + SignalLink() = default; -protected: - SignalLinkBase() = default; + SignalLink(const SignalLink&) = default; + SignalLink& operator=(const SignalLink&) = default; - SignalLinkBase(const SignalLinkBase&) = default; - SignalLinkBase& operator=(const SignalLinkBase&) = default; + SignalLink(SignalLink&&) = default; + SignalLink& operator=(SignalLink&&) = default; - SignalLinkBase(SignalLinkBase&&) = default; - SignalLinkBase& operator=(SignalLinkBase&&) = default; + // Construct with explicit group + SignalLink(const ReactiveGroup& group, const Signal& input) : + SignalLink::Signal( REACT_IMPL::CtorTag{ }, CreateLinkNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), input) ) + { } + + // Construct with implicit group + explicit SignalLink(const Signal& input) : + SignalLink::Signal( REACT_IMPL::CtorTag{ }, CreateLinkNode(REACT_IMPL::PrivateNodeInterface::GraphPtr(input), input) ) + { } - static auto CreateLinkNode(const std::shared_ptr& graphPtr, const SignalBase& input) -> decltype(auto) +protected: + static auto CreateLinkNode(const std::shared_ptr& graphPtr, const Signal& input) -> decltype(auto) { using REACT_IMPL::PrivateNodeInterface; using REACT_IMPL::PrivateReactiveGroupInterface; @@ -240,307 +285,12 @@ class SignalLinkBase : public SignalBase friend struct REACT_IMPL::PrivateSignalLinkNodeInterface; }; -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Signal -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -class Signal : public SignalBase -{ -public: - using SignalBase::SignalBase; - - using ValueType = S; - - Signal() = delete; - - Signal(const Signal&) = delete; - Signal& operator=(const Signal&) = delete; - - Signal(Signal&&) = default; - Signal& operator=(Signal&&) = default; - - // Construct from VarSignal - Signal(const VarSignalBase& other) : - Signal::SignalBase( other ) - { } - - // Construct func signal with explicit group - template - explicit Signal(const ReactiveGroupBase& group, F&& func, const SignalBase& dep1, const SignalBase& ... deps) : - Signal::SignalBase( REACT_IMPL::CtorTag{ }, CreateFuncNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), std::forward(func), dep1, deps ...) ) - { } - - // Construct func signal with implicit group - template - explicit Signal(F&& func, const SignalBase& dep1, const SignalBase& ... deps) : - Signal::SignalBase( REACT_IMPL::CtorTag{ }, CreateFuncNode(REACT_IMPL::PrivateNodeInterface::GraphPtr(dep1), std::forward(func), dep1, deps ...) ) - { } -}; - -template -class Signal : public SignalBase -{ -public: - using SignalBase::SignalBase; - - using ValueType = S; - - Signal() = delete; - - Signal(const Signal&) = default; - Signal& operator=(const Signal&) = default; - - Signal(Signal&&) = default; - Signal& operator=(Signal&&) = default; - - // Construct from VarSignal - Signal(const VarSignalBase& other) : - Signal::SignalBase( other ) - { } - - // Construct from unique - Signal(Signal&& other) : - Signal::SignalBase( std::move(other) ) - { } - - // Assign from unique - Signal& operator=(Signal&& other) - { Signal::SignalBase::operator=(std::move(other)); return *this; } - - // Construct func signal with explicit group - template - explicit Signal(const ReactiveGroupBase& group, F&& func, const SignalBase& dep1, const SignalBase& ... deps) : - Signal::SignalBase( REACT_IMPL::CtorTag{ }, CreateFuncNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), std::forward(func), dep1, deps ...) ) - { } - - // Construct func signal with implicit group - template - explicit Signal(F&& func, const SignalBase& dep1, const SignalBase& ... deps) : - Signal::SignalBase( REACT_IMPL::CtorTag{ }, CreateFuncNode(REACT_IMPL::PrivateNodeInterface::GraphPtr(dep1), std::forward(func), dep1, deps ...) ) - { } -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// VarSignal -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -class VarSignal : public VarSignalBase -{ -public: - using VarSignalBase::VarSignalBase; - - using ValueType = S; - - VarSignal() = delete; - - VarSignal(const VarSignal&) = delete; - VarSignal& operator=(const VarSignal&) = delete; - - VarSignal(VarSignal&&) = default; - VarSignal& operator=(VarSignal&&) = default; - - // Construct with group + default - explicit VarSignal(const ReactiveGroupBase& group) : - VarSignal::VarSignalBase( REACT_IMPL::CtorTag{ }, CreateVarNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group)) ) - { } - - // Construct with group + value - template - VarSignal(const ReactiveGroupBase& group, T&& value) : - VarSignal::VarSignalBase( REACT_IMPL::CtorTag{ }, CreateVarNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), std::forward(value)) ) - { } -}; - -template -class VarSignal : public VarSignalBase -{ -public: - using VarSignalBase::VarSignalBase; - - using ValueType = S; - - VarSignal() = delete; - - VarSignal(const VarSignal&) = default; - VarSignal& operator=(const VarSignal&) = default; - - VarSignal(VarSignal&&) = default; - VarSignal& operator=(VarSignal&&) = default; - - // Construct from unique - VarSignal(VarSignal&& other) : - VarSignal::VarSignalBase( std::move(other) ) - { } - - // Assign from unique - VarSignal& operator=(VarSignal&& other) - { VarSignal::VarSignalBase::operator=(std::move(other)); return *this; } - - // Construct with default - explicit VarSignal(const ReactiveGroupBase& group) : - VarSignal::VarSignalBase( REACT_IMPL::CtorTag{ }, CreateVarNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group)) ) - { } - - // Construct with value - template - VarSignal(const ReactiveGroupBase& group, T&& value) : - VarSignal::VarSignalBase( REACT_IMPL::CtorTag{ }, CreateVarNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), std::forward(value)) ) - { } -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// SignalSlot -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -class SignalSlot : public SignalSlotBase -{ -public: - using SignalSlotBase::SignalSlotBase; - - using ValueType = S; - - SignalSlot() = delete; - - SignalSlot(const SignalSlot&) = delete; - SignalSlot& operator=(const SignalSlot&) = delete; - - SignalSlot(SignalSlot&&) = default; - SignalSlot& operator=(SignalSlot&&) = default; - - // Construct with group + default - explicit SignalSlot(const ReactiveGroupBase& group) : - SignalSlot::SignalSlotBase( REACT_IMPL::CtorTag{ }, CreateSlotNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group)) ) - { } - - // Construct with group + value - SignalSlot(const ReactiveGroupBase& group, const SignalBase& input) : - SignalSlot::SignalSlotBase( REACT_IMPL::CtorTag{ }, CreateSlotNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), input) ) - { } - - // Construct with value - explicit SignalSlot(const SignalBase& input) : - SignalSlot::SignalSlotBase( REACT_IMPL::CtorTag{ }, CreateSlotNode(REACT_IMPL::PrivateNodeInterface::GraphPtr(input), input) ) - { } -}; - -template -class SignalSlot : public SignalSlotBase -{ -public: - using SignalSlotBase::SignalSlotBase; - - using ValueType = S; - - SignalSlot() = delete; - - SignalSlot(const SignalSlot&) = default; - SignalSlot& operator=(const SignalSlot&) = default; - - SignalSlot(SignalSlot&&) = default; - SignalSlot& operator=(SignalSlot&&) = default; - - // Construct from unique - SignalSlot(SignalSlot&& other) : - SignalSlot::SignalSlotBase( std::move(other) ) - { } - - // Assign from unique - SignalSlot& operator=(SignalSlot&& other) - { SignalSlot::SignalSlotBase::operator=(std::move(other)); return *this; } - - // Construct with group + default - explicit SignalSlot(const ReactiveGroupBase& group) : - SignalSlot::SignalSlotBase( REACT_IMPL::CtorTag{ }, CreateSlotNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group)) ) - { } - - // Construct with group + value - SignalSlot(const ReactiveGroupBase& group, const SignalBase& input) : - SignalSlot::SignalSlotBase( REACT_IMPL::CtorTag{ }, CreateSlotNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), input) ) - { } - - // Construct with value - explicit SignalSlot(const SignalBase& input) : - SignalSlot::SignalSlotBase( REACT_IMPL::CtorTag{ }, CreateSlotNode(REACT_IMPL::PrivateNodeInterface::GraphPtr(input), input) ) - { } -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// SignalLink -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -class SignalLink : public SignalLinkBase -{ -public: - using SignalLinkBase::SignalLinkBase; - - using ValueType = S; - - SignalLink() = delete; - - SignalLink(const SignalLink&) = delete; - SignalLink& operator=(const SignalLink&) = delete; - - SignalLink(SignalLink&&) = default; - SignalLink& operator=(SignalLink&&) = default; - - // Construct with default - explicit SignalLink(const ReactiveGroupBase& group) : - SignalLink::SignalLinkBase( REACT_IMPL::CtorTag{ }, CreateLinkNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group)) ) - { } - - // Construct with group + value - SignalLink(const ReactiveGroupBase& group, const SignalBase& input) : - SignalLink::SignalLinkBase( REACT_IMPL::CtorTag{ }, CreateLinkNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), input) ) - { } - - // Construct with value - explicit SignalLink(const SignalBase& input) : - SignalLink::SignalLinkBase( REACT_IMPL::CtorTag{ }, CreateLinkNode(REACT_IMPL::PrivateNodeInterface::GraphPtr(input), input) ) - { } -}; - -template -class SignalLink : public SignalLinkBase -{ -public: - using SignalLinkBase::SignalLinkBase; - - using ValueType = S; - - SignalLink() = delete; - - SignalLink(const SignalLink&) = default; - SignalLink& operator=(const SignalLink&) = default; - - SignalLink(SignalLink&&) = default; - SignalLink& operator=(SignalLink&&) = default; - - // Construct from unique - SignalLink(SignalLink&& other) : - SignalLink::SignalLinkBase( std::move(other) ) - { } - - // Assign from unique - SignalLink& operator=(SignalSlot&& other) - { SignalLink::SignalLinkBase::operator=(std::move(other)); return *this; } - - // Construct with default - explicit SignalLink(const ReactiveGroupBase& group) : - SignalLink::SignalLinkBase( REACT_IMPL::CtorTag{ }, CreateLinkNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group)) ) - { } - - // Construct with value - SignalLink(const ReactiveGroupBase& group, const SignalBase& input) : - SignalLink::SignalLinkBase( REACT_IMPL::CtorTag{ }, CreateLinkNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), input) ) - { } -}; - /******************************************/ REACT_END /******************************************/ /***************************************/ REACT_IMPL_BEGIN /**************************************/ template -bool Equals(const SignalBase& lhs, const SignalBase& rhs) +bool Equals(const Signal& lhs, const Signal& rhs) { return lhs.Equals(rhs); } @@ -548,7 +298,7 @@ bool Equals(const SignalBase& lhs, const SignalBase& rhs) struct PrivateSignalLinkNodeInterface { template - static auto GetLocalNodePtr(const std::shared_ptr& targetGraph, const SignalBase& sig) -> std::shared_ptr> + static auto GetLocalNodePtr(const std::shared_ptr& targetGraph, const Signal& sig) -> std::shared_ptr> { const std::shared_ptr& sourceGraph = PrivateNodeInterface::GraphPtr(sig); From 6ce444005409811361a8be2270b297881e753b89 Mon Sep 17 00:00:00 2001 From: schlangster Date: Sun, 18 Dec 2016 16:45:44 +0100 Subject: [PATCH 42/75] refactor wip --- examples/src/Main.cpp | 56 ++++++------ include/react/Event.h | 4 +- include/react/Observer.h | 186 ++++++++++++--------------------------- 3 files changed, 84 insertions(+), 162 deletions(-) diff --git a/examples/src/Main.cpp b/examples/src/Main.cpp index 47a9494c..653d9d5e 100644 --- a/examples/src/Main.cpp +++ b/examples/src/Main.cpp @@ -22,7 +22,7 @@ template class GridGraphGenerator { public: - using SignalType = Signal; + using SignalType = Signal; using Func1T = std::function; using Func2T = std::function; @@ -37,7 +37,7 @@ class GridGraphGenerator std::vector widths; - void Generate(const ReactiveGroupBase& group) + void Generate(const ReactiveGroup& group) { assert(inputSignals.size() >= 1); assert(widths.size() >= 1); @@ -160,9 +160,9 @@ template T IterFunc2(EventRange evts, T v, T a1, T a2) return v + 1; } -int main() +int main2() { - ReactiveGroup<> group; + ReactiveGroup group; { // Signals @@ -173,8 +173,8 @@ int main() Signal area{ Multiply, x, y }; Signal volume{ Multiply, area, z }; - Observer<> areaObs{ PrintArea, area }; - Observer<> volumeObs{ PrintVolume, volume }; + Observer areaObs{ PrintArea, area }; + Observer volumeObs{ PrintVolume, volume }; x.Set(2); // a: 0, v: 0 y.Set(2); // a: 4, v: 0 @@ -198,7 +198,7 @@ int main() Event anyButton = Merge(button1, button2); Event filtered = Filter(FilterFunc, anyButton); - Observer<> eventObs{ PrintEvents, anyButton }; + Observer eventObs{ PrintEvents, anyButton }; button1.Emit(1); button2.Emit(2); @@ -217,7 +217,7 @@ int main() SignalSlot slot{ s1 }; - Observer<> areaObs{ PrintValue, slot }; + Observer areaObs{ PrintValue, slot }; s1.Set(42); @@ -228,15 +228,15 @@ int main() // Links { - ReactiveGroup<> group1; - ReactiveGroup<> group2; + ReactiveGroup group1; + ReactiveGroup group2; VarSignal s1{ group1, 10 }; VarSignal s2{ group2, 11 }; Signal v{ Multiply, s1, s2 }; - Observer<> obs{ PrintValue, v }; + Observer obs{ PrintValue, v }; s1.Set(555); @@ -244,8 +244,8 @@ int main() } { - ReactiveGroup<> group1; - ReactiveGroup<> group2; + ReactiveGroup group1; + ReactiveGroup group2; VarSignal s1{ group1, 10 }; VarSignal s2{ group2, 11 }; @@ -260,8 +260,8 @@ int main() auto joined1 = Join(e1, e2); auto joined2 = Join(group1, e1, e2); - Observer<> eventObs1{ PrintEvents, merged }; - Observer<> eventObs2{ group2, PrintSyncedEvents, merged, s1, s2 }; + Observer eventObs1{ PrintEvents, merged }; + Observer eventObs2{ group2, PrintSyncedEvents, merged, s1, s2 }; e1.Emit(222); @@ -269,8 +269,8 @@ int main() } { - ReactiveGroup<> group1; - ReactiveGroup<> group2; + ReactiveGroup group1; + ReactiveGroup group2; VarSignal s1{ group1, 10 }; VarSignal s2{ group2, 11 }; @@ -301,8 +301,8 @@ int main() auto iter3 = Iterate(group, 0, IterFunc2, e1, s1, s2); auto iter4 = Iterate(0, IterFunc2, e1, s1, s2); - Observer<> eventObs{ PrintEvents, merged }; - Observer<> eventObs2{ group2, PrintSyncedEvents, merged, s1, s2 }; + Observer eventObs{ PrintEvents, merged }; + Observer eventObs2{ group2, PrintSyncedEvents, merged, s1, s2 }; e1.Emit(222); @@ -326,10 +326,10 @@ int main() int main() { - ReactiveGroup<> group; + ReactiveGroup group; - VarSignal in{ group, 1 }; - Signal in2 = in; + VarSignal in{ group, 1 }; + Signal in2 = in; GridGraphGenerator generator; @@ -376,9 +376,9 @@ int main() /*int main2() { - ReactiveGroup<> group1; - ReactiveGroup<> group2; - ReactiveGroup<> group3; + ReactiveGroup group1; + ReactiveGroup group2; + ReactiveGroup group3; VarSignal x{ 0, group1 }; VarSignal y{ 0, group2 }; @@ -387,7 +387,7 @@ int main() Signal area{ Multiply, x, y }; Signal volume{ Multiply, area, z }; - Observer<> obs{ PrintAreaAndVolume, area, volume }; + Observer obs{ PrintAreaAndVolume, area, volume }; Signal> volumeHistory = Iterate>( vector{ }, PushToVector, Monitor(volume)); @@ -420,8 +420,8 @@ int main3() using namespace std; using namespace react; - ReactiveGroup<> group1; - ReactiveGroup<> group2; + ReactiveGroup group1; + ReactiveGroup group2; auto sig1 = VarSignal( 10, group1 ); diff --git a/include/react/Event.h b/include/react/Event.h index da63eb35..54d1ec85 100644 --- a/include/react/Event.h +++ b/include/react/Event.h @@ -294,7 +294,7 @@ auto Merge(const ReactiveGroup& group, const Event& dep1, const Event& . const auto& graphPtr = PrivateReactiveGroupInterface::GraphPtr(group); - return Event( CtorTag{ }, std::make_shared>( + return Event( CtorTag{ }, std::make_shared>( graphPtr, PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, dep1), PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, deps) ...)); } @@ -316,7 +316,7 @@ auto Merge(const Event& dep1, const Event& ... deps) -> decltype(auto) const auto& graphPtr = PrivateNodeInterface::GraphPtr(dep1); - return Event( CtorTag{ }, std::make_shared>( + return Event( CtorTag{ }, std::make_shared>( graphPtr, PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, dep1), PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, deps) ...)); } diff --git a/include/react/Observer.h b/include/react/Observer.h index eea9ce5f..8d2be2a9 100644 --- a/include/react/Observer.h +++ b/include/react/Observer.h @@ -23,16 +23,55 @@ /////////////////////////////////////////////////////////////////////////////////////////////////// /// ObserverBase /////////////////////////////////////////////////////////////////////////////////////////////////// -class ObserverBase +class Observer { private: using NodeType = REACT_IMPL::ObserverNode; public: - // Private node ctor - explicit ObserverBase(std::shared_ptr&& nodePtr) : - nodePtr_( std::move(nodePtr) ) - { } + Observer() = default; + + Observer(const Observer&) = default; + Observer& operator=(const Observer&) = default; + + Observer(Observer&&) = default; + Observer& operator=(Observer&&) = default; + + // Construct signal observer with implicit group + template + Observer(F&& func, const Signal& ... subjects) : + Observer::Observer(CreateSignalObserverNode(std::forward(func), subjects ...)) + { } + + // Construct signal observer with explicit group + template + Observer(const ReactiveGroup& group, F&& func, const Signal& ... subjects) : + Observer::Observer(CreateSignalObserverNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), std::forward(func), subjects ...)) + { } + + // Construct event observer with implicit group + template + Observer(F&& func, const Event& subject) : + Observer::Observer(CreateEventObserverNode(std::forward(func), subject)) + { } + + // Construct event observer with explicit group + template + Observer(const ReactiveGroup& group, F&& func, const Event& subject) : + Observer::Observer(CreateEventObserverNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), std::forward(func), subject)) + { } + + // Constructed synced event observer with implicit group + template + Observer(F&& func, const Event& subject, const Signal& ... signals) : + Observer::Observer(CreateSyncedEventObserverNode(std::forward(func), subject, signals ...)) + { } + + // Constructed synced event observer with explicit group + template + Observer(const ReactiveGroup& group, F&& func, const Event& subject, const Signal& ... signals) : + Observer::Observer(CreateSyncedEventObserverNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), std::forward(func), subject, signals ...)) + { } void Cancel() { nodePtr_.reset(); } @@ -41,13 +80,10 @@ class ObserverBase { return nodePtr_ != nullptr; } protected: - ObserverBase() = default; - - ObserverBase(const ObserverBase&) = default; - ObserverBase& operator=(const ObserverBase&) = default; - - ObserverBase(ObserverBase&&) = default; - ObserverBase& operator=(ObserverBase&&) = default; + // Private node ctor + explicit Observer(std::shared_ptr&& nodePtr) : + nodePtr_(std::move(nodePtr)) + { } auto NodePtr() -> std::shared_ptr& { return nodePtr_; } @@ -56,7 +92,7 @@ class ObserverBase { return nodePtr_; } template - auto CreateSignalObserverNode(const std::shared_ptr& graphPtr, F&& func, const SignalBase& dep1, const SignalBase& ... deps) -> decltype(auto) + auto CreateSignalObserverNode(const std::shared_ptr& graphPtr, F&& func, const Signal& dep1, const Signal& ... deps) -> decltype(auto) { using REACT_IMPL::PrivateSignalLinkNodeInterface; using ObsNodeType = REACT_IMPL::SignalObserverNode::type, T1, Ts ...>; @@ -68,14 +104,14 @@ class ObserverBase } template - auto CreateSignalObserverNode(F&& func, const SignalBase& dep1, const SignalBase& ... deps) -> decltype(auto) + auto CreateSignalObserverNode(F&& func, const Signal& dep1, const Signal& ... deps) -> decltype(auto) { using REACT_IMPL::PrivateNodeInterface; return CreateSignalObserverNode(PrivateNodeInterface::GraphPtr(dep1), std::forward(func), dep1, deps ...); } template - auto CreateEventObserverNode(const std::shared_ptr& graphPtr, F&& func, const EventBase& dep) -> decltype(auto) + auto CreateEventObserverNode(const std::shared_ptr& graphPtr, F&& func, const Event& dep) -> decltype(auto) { using REACT_IMPL::PrivateEventLinkNodeInterface; using ObsNodeType = REACT_IMPL::EventObserverNode::type, T>; @@ -84,14 +120,14 @@ class ObserverBase } template - auto CreateEventObserverNode(F&& func, const EventBase& dep) -> decltype(auto) + auto CreateEventObserverNode(F&& func, const Event& dep) -> decltype(auto) { using REACT_IMPL::PrivateNodeInterface; return CreateEventObserverNode(PrivateNodeInterface::GraphPtr(dep), std::forward(func), dep); } template - auto CreateSyncedEventObserverNode(const std::shared_ptr& graphPtr, F&& func, const EventBase& dep, const SignalBase& ... syncs) -> decltype(auto) + auto CreateSyncedEventObserverNode(const std::shared_ptr& graphPtr, F&& func, const Event& dep, const Signal& ... syncs) -> decltype(auto) { using REACT_IMPL::PrivateEventLinkNodeInterface; using REACT_IMPL::PrivateSignalLinkNodeInterface; @@ -102,7 +138,7 @@ class ObserverBase } template - auto CreateSyncedEventObserverNode(F&& func, const EventBase& dep, const SignalBase& ... syncs) -> decltype(auto) + auto CreateSyncedEventObserverNode(F&& func, const Event& dep, const Signal& ... syncs) -> decltype(auto) { using REACT_IMPL::PrivateNodeInterface; return CreateSyncedEventObserverNode(PrivateNodeInterface::GraphPtr(dep), std::forward(func), dep, syncs ...); @@ -114,120 +150,6 @@ class ObserverBase friend struct REACT_IMPL::PrivateNodeInterface; }; -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Observer -/////////////////////////////////////////////////////////////////////////////////////////////////// -template <> -class Observer : public ObserverBase -{ -public: - using ObserverBase::ObserverBase; - - Observer() = delete; - - Observer(const Observer&) = delete; - Observer& operator=(const Observer&) = delete; - - Observer(Observer&&) = default; - Observer& operator=(Observer&&) = default; - - // Construct signal observer with implicit group - template - Observer(F&& func, const SignalBase& ... subjects) : - Observer::ObserverBase( CreateSignalObserverNode(std::forward(func), subjects ...) ) - { } - - // Construct signal observer with explicit group - template - Observer(const ReactiveGroupBase& group, F&& func, const SignalBase& ... subjects) : - Observer::ObserverBase( CreateSignalObserverNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), std::forward(func), subjects ...) ) - { } - - // Construct event observer with implicit group - template - Observer(F&& func, const EventBase& subject) : - Observer::ObserverBase( CreateEventObserverNode(std::forward(func), subject) ) - { } - - // Construct event observer with explicit group - template - Observer(const ReactiveGroupBase& group, F&& func, const EventBase& subject) : - Observer::ObserverBase( CreateEventObserverNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), std::forward(func), subject) ) - { } - - // Constructed synced event observer with implicit group - template - Observer(F&& func, const EventBase& subject, const SignalBase& ... signals) : - Observer::ObserverBase( CreateSyncedEventObserverNode(std::forward(func), subject, signals ...) ) - { } - - // Constructed synced event observer with explicit group - template - Observer(const ReactiveGroupBase& group, F&& func, const EventBase& subject, const SignalBase& ... signals) : - Observer::ObserverBase( CreateSyncedEventObserverNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), std::forward(func), subject, signals ...) ) - { } -}; - -template <> -class Observer : public ObserverBase -{ -public: - using ObserverBase::ObserverBase; - - Observer() = delete; - - Observer(const Observer&) = default; - Observer& operator=(const Observer&) = default; - - Observer(Observer&&) = default; - Observer& operator=(Observer&&) = default; - - // Construct from unique - Observer(Observer&& other) : - Observer::ObserverBase( std::move(other) ) - { } - - // Assign from unique - Observer& operator=(Observer&& other) - { Observer::ObserverBase::operator=(std::move(other)); return *this; } - - // Construct signal observer with implicit group - template - Observer(F&& func, const SignalBase& ... subjects) : - Observer::ObserverBase( CreateSignalObserverNode(std::forward(func), subjects ...) ) - { } - - // Construct signal observer with explicit group - template - Observer(const ReactiveGroupBase& group, F&& func, const SignalBase& ... subjects) : - Observer::ObserverBase( CreateSignalObserverNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), std::forward(func), subjects ...) ) - { } - - // Construct event observer with implicit group - template - Observer(F&& func, const EventBase& subject) : - Observer::ObserverBase( CreateEventObserverNode(std::forward(func), subject) ) - { } - - // Construct event observer with explicit group - template - Observer(const ReactiveGroupBase& group, F&& func, const EventBase& subject) : - Observer::ObserverBase( CreateEventObserverNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), std::forward(func), subject) ) - { } - - // Constructed synced event observer with implicit group - template - Observer(F&& func, const EventBase& subject, const SignalBase& ... signals) : - Observer::ObserverBase( CreateSyncedEventObserverNode(std::forward(func), subject, signals ...) ) - { } - - // Constructed synced event observer with explicit group - template - Observer(const ReactiveGroupBase& group, F&& func, const EventBase& subject, const SignalBase& ... signals) : - Observer::ObserverBase( CreateSyncedEventObserverNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), std::forward(func), subject, signals ...) ) - { } -}; - /******************************************/ REACT_END /******************************************/ #endif // REACT_OBSERVER_H_INCLUDED \ No newline at end of file From b7ec9da43ede547eaa0b42d61b79047cc168d722 Mon Sep 17 00:00:00 2001 From: schlangster Date: Sun, 18 Dec 2016 22:31:10 +0100 Subject: [PATCH 43/75] done getting rid of unique/shared wrapper types. everything is shared by default now. --- examples/src/BasicAlgorithms.cpp | 16 +++---- examples/src/BasicEvents.cpp | 22 +++++----- examples/src/BasicObservers.cpp | 8 ++-- examples/src/BasicSignals.cpp | 16 +++---- include/react/Algorithm.h | 62 +++++++++++++-------------- include/react/Event.h | 42 +++++++++--------- include/react/Group.h | 6 +++ include/react/Observer.h | 14 +++--- include/react/Signal.h | 8 ++-- project/msvc/CppReact.vcxproj | 1 - project/msvc/CppReact.vcxproj.filters | 3 -- 11 files changed, 99 insertions(+), 99 deletions(-) diff --git a/examples/src/BasicAlgorithms.cpp b/examples/src/BasicAlgorithms.cpp index a11dbdb9..e804ec81 100644 --- a/examples/src/BasicAlgorithms.cpp +++ b/examples/src/BasicAlgorithms.cpp @@ -22,7 +22,7 @@ namespace example1 using namespace std; using namespace react; - ReactiveGroup<> group; + ReactiveGroup group; struct Sensor { @@ -36,7 +36,7 @@ namespace example1 Sensor mySensor; - Observer<> obs( + Observer obs( [] (int v) { cout << v << endl; @@ -62,7 +62,7 @@ namespace example2 using namespace std; using namespace react; - ReactiveGroup<> group; + ReactiveGroup group; struct Employee { @@ -76,7 +76,7 @@ namespace example2 Employee bob; - Observer<> obs( + Observer obs( [] (EventRange in, const string& name) { for (int newSalary : in) @@ -96,7 +96,7 @@ namespace example3 using namespace std; using namespace react; - ReactiveGroup<> group; + ReactiveGroup group; struct Counter { @@ -137,7 +137,7 @@ namespace example4 using namespace std; using namespace react; - ReactiveGroup<> group; + ReactiveGroup group; struct Sensor { @@ -188,7 +188,7 @@ namespace example5 using namespace std; using namespace react; - ReactiveGroup<> group; + ReactiveGroup group; enum ECmd { increment, decrement, reset }; @@ -255,7 +255,7 @@ namespace example6 using namespace std; using namespace react; - ReactiveGroup<> group; + ReactiveGroup group; class Sensor { diff --git a/examples/src/BasicEvents.cpp b/examples/src/BasicEvents.cpp index b9a7cfbd..97b795c2 100644 --- a/examples/src/BasicEvents.cpp +++ b/examples/src/BasicEvents.cpp @@ -22,7 +22,7 @@ namespace example1 // Defines a group. // Each group represents a separate dependency graph. // Reactives from different groups can not be mixed. - ReactiveGroup<> group; + ReactiveGroup group; // An event source that emits values of type string namespace v1 @@ -33,7 +33,7 @@ namespace example1 { cout << "Example 1 - Hello world (string source)" << endl; - Observer<> obs( + Observer obs( [] (EventRange in) { for (const auto& s : in) @@ -61,7 +61,7 @@ namespace example1 int count = 0; - Observer<> obs( + Observer obs( [&] (EventRange<> in) { for (auto t : in) @@ -87,7 +87,7 @@ namespace example2 using namespace std; using namespace react; - ReactiveGroup<> group; + ReactiveGroup group; // An event stream that merges both sources EventSource<> leftClick( group ); @@ -101,7 +101,7 @@ namespace example2 int count = 0; - Observer<> obs( + Observer obs( [&] (EventRange<> in) { for (auto t : in) @@ -124,7 +124,7 @@ namespace example3 using namespace std; using namespace react; - ReactiveGroup<> group; + ReactiveGroup group; EventSource numbers( group ); @@ -134,7 +134,7 @@ namespace example3 { cout << "Example 3 - Filtering events" << endl; - Observer<> obs( + Observer obs( [&] (EventRange in) { for (auto n : in) @@ -156,7 +156,7 @@ namespace example4 using namespace std; using namespace react; - ReactiveGroup<> group; + ReactiveGroup group; // Data types enum class Tag { normal, critical }; @@ -178,7 +178,7 @@ namespace example4 { cout << "Example 4 - Transforming events" << endl; - Observer<> obs( + Observer obs( [] (EventRange in) { for (TaggedNum e : in) @@ -206,7 +206,7 @@ namespace example5 using namespace std; using namespace react; - ReactiveGroup<> group; + ReactiveGroup group; EventSource src( group ); @@ -214,7 +214,7 @@ namespace example5 { cout << "Example 5 - Queuing multiple inputs" << endl; - Observer<> obs( + Observer obs( [] (EventRange in) { for (int e : in) diff --git a/examples/src/BasicObservers.cpp b/examples/src/BasicObservers.cpp index c81cb372..261e5b88 100644 --- a/examples/src/BasicObservers.cpp +++ b/examples/src/BasicObservers.cpp @@ -20,7 +20,7 @@ namespace example1 using namespace std; using namespace react; - ReactiveGroup<> group; + ReactiveGroup group; VarSignal x( group, 1 ); @@ -31,7 +31,7 @@ namespace example1 { Signal mySignal( [] (int x) { return x; }, x ); - Observer<> obs( [] (int mySignal) { cout << mySignal << endl; }, mySignal ); + Observer obs( [] (int mySignal) { cout << mySignal << endl; }, mySignal ); x <<= 2; // output: 2 } @@ -50,7 +50,7 @@ namespace example2 using namespace std; using namespace react; - ReactiveGroup<> group; + ReactiveGroup group; EventSource<> trigger( group ); @@ -58,7 +58,7 @@ namespace example2 { cout << "Example 2 - Detaching observers manually" << endl; - Observer<> obs( + Observer obs( [] (EventRange<> in) { for (auto _ : in) diff --git a/examples/src/BasicSignals.cpp b/examples/src/BasicSignals.cpp index fc52eb68..995872dd 100644 --- a/examples/src/BasicSignals.cpp +++ b/examples/src/BasicSignals.cpp @@ -29,7 +29,7 @@ namespace example1 // Defines a group. // Each group represents a separate dependency graph. // Reactives from different groups can not be mixed. - ReactiveGroup<> group; + ReactiveGroup group; // The two words VarSignal firstWord( group, string("Change") ); @@ -64,7 +64,7 @@ namespace example2 using namespace std; using namespace react; - ReactiveGroup<> group; + ReactiveGroup group; VarSignal x( group, 1 ); @@ -74,7 +74,7 @@ namespace example2 { cout << "Example 2 - Reacting to value changes" << endl; - Observer<> obs( + Observer obs( [] (int newValue) { cout << "xAbs changed to " << newValue << endl; }, xAbs ); @@ -98,7 +98,7 @@ namespace example3 int sumFunc(int a, int b) { return a + b; } - ReactiveGroup<> group; + ReactiveGroup group; VarSignal a( group, 1 ); VarSignal b( group, 1 ); @@ -111,7 +111,7 @@ namespace example3 { cout << "Example 3 - Changing multiple inputs" << endl; - Observer<> obs( + Observer obs( [] (int newValue) { cout << "z changed to " << newValue << endl; }, z ); @@ -136,7 +136,7 @@ namespace example4 using namespace std; using namespace react; - ReactiveGroup<> group; + ReactiveGroup group; VarSignal> data( group ); @@ -167,7 +167,7 @@ namespace example5 using namespace std; using namespace react; - ReactiveGroup<> group; + ReactiveGroup group; // Helpers using ExprPairType = pair; @@ -204,7 +204,7 @@ namespace example5 { cout << "Example 5 - Complex signals (v3)" << endl; - Observer<> obs(PrintExpressions, expressions); + Observer obs(PrintExpressions, expressions); a <<= 50; b <<= 60; diff --git a/include/react/Algorithm.h b/include/react/Algorithm.h index b7e8324d..f9ab8bb7 100644 --- a/include/react/Algorithm.h +++ b/include/react/Algorithm.h @@ -32,12 +32,13 @@ auto Hold(const ReactiveGroup& group, T&& initialValue, const Event& evnt) -> using REACT_IMPL::HoldNode; using REACT_IMPL::PrivateEventLinkNodeInterface; using REACT_IMPL::PrivateReactiveGroupInterface; + using REACT_IMPL::PrivateNodeInterface; using REACT_IMPL::CtorTag; const auto& graphPtr = PrivateReactiveGroupInterface::GraphPtr(group); - return Signal( CtorTag{ }, std::make_shared>( - graphPtr, std::forward(initialValue), PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, evnt)) ); + return PrivateNodeInterface::CreateNodeHelper, HoldNode>( + graphPtr, std::forward(initialValue), PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, evnt)); } template @@ -50,8 +51,8 @@ auto Hold(T&& initialValue, const Event& evnt) -> Signal const auto& graphPtr = PrivateNodeInterface::GraphPtr(evnt); - return Signal( CtorTag{ }, std::make_shared>( - graphPtr, std::forward(initialValue), PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, evnt)) ); + return PrivateNodeInterface::CreateNodeHelper, HoldNode>( + graphPtr, std::forward(initialValue), PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, evnt)); } /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -63,12 +64,12 @@ auto Monitor(const ReactiveGroup& group, const Signal& signal) -> Event using REACT_IMPL::MonitorNode; using REACT_IMPL::PrivateSignalLinkNodeInterface; using REACT_IMPL::PrivateReactiveGroupInterface; - using REACT_IMPL::CtorTag; + using REACT_IMPL::PrivateNodeInterface; const auto& graphPtr = PrivateReactiveGroupInterface::GraphPtr(group); - return Event( CtorTag{ }, std::make_shared>( - graphPtr, PrivateSignalLinkNodeInterface::GetLocalNodePtr(graphPtr, signal)) ); + return PrivateNodeInterface::CreateNodeHelper, MonitorNode>( + graphPtr, PrivateSignalLinkNodeInterface::GetLocalNodePtr(graphPtr, signal)); } template @@ -77,12 +78,11 @@ auto Monitor(const Signal& signal) -> Event using REACT_IMPL::MonitorNode; using REACT_IMPL::PrivateSignalLinkNodeInterface; using REACT_IMPL::PrivateNodeInterface; - using REACT_IMPL::CtorTag; const auto& graphPtr = PrivateNodeInterface::GraphPtr(signal); - return Event( CtorTag{ }, std::make_shared>( - graphPtr, PrivateSignalLinkNodeInterface::GetLocalNodePtr(graphPtr, signal)) ); + return PrivateNodeInterface::CreateNodeHelper, MonitorNode>( + graphPtr, PrivateSignalLinkNodeInterface::GetLocalNodePtr(graphPtr, signal)); } /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -96,7 +96,7 @@ auto Iterate(const ReactiveGroup& group, T&& initialValue, F&& func, const Event using REACT_IMPL::IsCallableWith; using REACT_IMPL::PrivateEventLinkNodeInterface; using REACT_IMPL::PrivateReactiveGroupInterface; - using REACT_IMPL::CtorTag; + using REACT_IMPL::PrivateNodeInterface; using FuncType = typename std::decay::type; using IterNodeType = typename std::conditional< @@ -106,8 +106,8 @@ auto Iterate(const ReactiveGroup& group, T&& initialValue, F&& func, const Event const auto& graphPtr = PrivateReactiveGroupInterface::GraphPtr(group); - return Signal( CtorTag{ }, std::make_shared( - graphPtr, std::forward(initialValue), std::forward(func), PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, evnt) )); + return PrivateNodeInterface::CreateNodeHelper, IterNodeType>( + graphPtr, std::forward(initialValue), std::forward(func), PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, evnt)); } template @@ -128,8 +128,8 @@ auto Iterate(T&& initialValue, F&& func, const Event& evnt) -> Signal const auto& graphPtr = PrivateNodeInterface::GraphPtr(evnt); - return Signal( CtorTag{ }, std::make_shared( - graphPtr, std::forward(initialValue), std::forward(func), PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, evnt) )); + return PrivateNodeInterface::CreateNodeHelper, IterNodeType>( + graphPtr, std::forward(initialValue), std::forward(func), PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, evnt)); } /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -144,7 +144,7 @@ auto Iterate(const ReactiveGroup& group, T&& initialValue, F&& func, const Event using REACT_IMPL::PrivateSignalLinkNodeInterface; using REACT_IMPL::PrivateEventLinkNodeInterface; using REACT_IMPL::PrivateReactiveGroupInterface; - using REACT_IMPL::CtorTag; + using REACT_IMPL::PrivateNodeInterface; using FuncType = typename std::decay::type; using IterNodeType = typename std::conditional< @@ -154,9 +154,9 @@ auto Iterate(const ReactiveGroup& group, T&& initialValue, F&& func, const Event const auto& graphPtr = PrivateReactiveGroupInterface::GraphPtr(group); - return Signal( CtorTag{ }, std::make_shared( + return PrivateNodeInterface::CreateNodeHelper, IterNodeType>( graphPtr, std::forward(initialValue), std::forward(func), - PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, evnt), PrivateSignalLinkNodeInterface::GetLocalNodePtr(graphPtr, signals) ...)); + PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, evnt), PrivateSignalLinkNodeInterface::GetLocalNodePtr(graphPtr, signals) ...); } template @@ -168,7 +168,6 @@ auto Iterate(T&& initialValue, F&& func, const Event& evnt, const Signal& using REACT_IMPL::PrivateSignalLinkNodeInterface; using REACT_IMPL::PrivateEventLinkNodeInterface;; using REACT_IMPL::PrivateNodeInterface; - using REACT_IMPL::CtorTag; using FuncType = typename std::decay::type; using IterNodeType = typename std::conditional< @@ -178,9 +177,9 @@ auto Iterate(T&& initialValue, F&& func, const Event& evnt, const Signal& const auto& graphPtr = PrivateNodeInterface::GraphPtr(evnt); - return Signal( CtorTag{ }, std::make_shared( + return PrivateNodeInterface::CreateNodeHelper, IterNodeType>( graphPtr, std::forward(initialValue), std::forward(func), - PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, evnt), PrivateSignalLinkNodeInterface::GetLocalNodePtr(graphPtr, signals) ...)); + PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, evnt), PrivateSignalLinkNodeInterface::GetLocalNodePtr(graphPtr, signals) ...); } /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -193,12 +192,12 @@ auto Snapshot(const ReactiveGroup& group, const Signal& signal, const Event( CtorTag{ }, std::make_shared>( - graphPtr, PrivateSignalLinkNodeInterface::GetLocalNodePtr(graphPtr, signal), PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, evnt)) ); + return PrivateNodeInterface::CreateNodeHelper, SnapshotNode>( + graphPtr, PrivateSignalLinkNodeInterface::GetLocalNodePtr(graphPtr, signal), PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, evnt)); } template @@ -208,12 +207,11 @@ auto Snapshot(const Signal& signal, const Event& evnt) -> Signal using REACT_IMPL::PrivateSignalLinkNodeInterface; using REACT_IMPL::PrivateEventLinkNodeInterface;; using REACT_IMPL::PrivateNodeInterface; - using REACT_IMPL::CtorTag; const auto& graphPtr = PrivateNodeInterface::GraphPtr(signal); - return Signal( CtorTag{ }, std::make_shared>( - graphPtr, PrivateSignalLinkNodeInterface::GetLocalNodePtr(graphPtr, signal), PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, evnt)) ); + return PrivateNodeInterface::CreateNodeHelper, SnapshotNode>( + graphPtr, PrivateSignalLinkNodeInterface::GetLocalNodePtr(graphPtr, signal), PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, evnt)); } /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -226,12 +224,12 @@ auto Pulse(const ReactiveGroup& group, const Signal& signal, const Event& using REACT_IMPL::PrivateSignalLinkNodeInterface; using REACT_IMPL::PrivateEventLinkNodeInterface;; using REACT_IMPL::PrivateReactiveGroupInterface; - using REACT_IMPL::CtorTag; + using REACT_IMPL::PrivateNodeInterface; const auto& graphPtr = PrivateReactiveGroupInterface::GraphPtr(group); - return Event( CtorTag{ }, std::make_shared>( - graphPtr, PrivateSignalLinkNodeInterface::GetLocalNodePtr(graphPtr, signal), PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, evnt)) ); + return PrivateNodeInterface::CreateNodeHelper, PulseNode>( + graphPtr, PrivateSignalLinkNodeInterface::GetLocalNodePtr(graphPtr, signal), PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, evnt)); } template @@ -245,8 +243,8 @@ auto Pulse(const Signal& signal, const Event& evnt) -> Event const auto& graphPtr = PrivateNodeInterface::GraphPtr(signal); - return Event( CtorTag{ }, std::make_shared>( - graphPtr, PrivateSignalLinkNodeInterface::GetLocalNodePtr(graphPtr, signal), PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, evnt)) ); + return PrivateNodeInterface::CreateNodeHelper, PulseNode>( + graphPtr, PrivateSignalLinkNodeInterface::GetLocalNodePtr(graphPtr, signal), PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, evnt)); } /******************************************/ REACT_END /******************************************/ diff --git a/include/react/Event.h b/include/react/Event.h index 54d1ec85..9151bc14 100644 --- a/include/react/Event.h +++ b/include/react/Event.h @@ -282,6 +282,7 @@ auto Merge(const ReactiveGroup& group, const Event& dep1, const Event& . using REACT_IMPL::EventMergeNode; using REACT_IMPL::PrivateEventLinkNodeInterface; using REACT_IMPL::PrivateReactiveGroupInterface; + using REACT_IMPL::PrivateNodeInterface; using REACT_IMPL::CtorTag; static_assert(sizeof...(Us) > 0, "Merge requires at least 2 inputs."); @@ -293,9 +294,9 @@ auto Merge(const ReactiveGroup& group, const Event& dep1, const Event& . T>::type; const auto& graphPtr = PrivateReactiveGroupInterface::GraphPtr(group); - - return Event( CtorTag{ }, std::make_shared>( - graphPtr, PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, dep1), PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, deps) ...)); + + return PrivateNodeInterface::CreateNodeHelper, EventMergeNode>( + graphPtr, PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, dep1), PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, deps) ...); } template @@ -316,8 +317,8 @@ auto Merge(const Event& dep1, const Event& ... deps) -> decltype(auto) const auto& graphPtr = PrivateNodeInterface::GraphPtr(dep1); - return Event( CtorTag{ }, std::make_shared>( - graphPtr, PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, dep1), PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, deps) ...)); + return PrivateNodeInterface::CreateNodeHelper, EventMergeNode>( + graphPtr, PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, dep1), PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, deps) ...); } /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -329,7 +330,7 @@ auto Filter(const ReactiveGroup& group, F&& pred, const Event& dep) -> Event< auto filterFunc = [capturedPred = std::forward(pred)] (EventRange inRange, EventSink out) { std::copy_if(inRange.begin(), inRange.end(), out, capturedPred); }; - return Event(group, std::move(filterFunc), dep); + return Event(group, std::move(filterFunc), dep); } template @@ -338,7 +339,7 @@ auto Filter(F&& pred, const Event& dep) -> Event auto filterFunc = [capturedPred = std::forward(pred)] (EventRange inRange, EventSink out) { std::copy_if(inRange.begin(), inRange.end(), out, capturedPred); }; - return Event(std::move(filterFunc), dep); + return Event(std::move(filterFunc), dep); } template @@ -351,7 +352,7 @@ auto Filter(const ReactiveGroup& group, F&& pred, const Event& dep, const Sig *out++ = v; }; - return Event(group, std::move(filterFunc), dep, signals ...); + return Event(group, std::move(filterFunc), dep, signals ...); } template @@ -364,7 +365,7 @@ auto Filter(F&& pred, const Event& dep, const Signal& ... signals) -> Eve *out++ = v; }; - return Event(std::move(filterFunc), dep, signals ...); + return Event(std::move(filterFunc), dep, signals ...); } /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -376,7 +377,7 @@ auto Transform(const ReactiveGroup& group, F&& op, const Event& dep) -> Event auto transformFunc = [capturedOp = std::forward(op)] (EventRange inRange, EventSink out) { std::transform(inRange.begin(), inRange.end(), out, capturedOp); }; - return Event(group, std::move(transformFunc), dep); + return Event(group, std::move(transformFunc), dep); } template @@ -385,7 +386,7 @@ auto Transform(F&& op, const Event& dep) -> Event auto transformFunc = [capturedOp = std::forward(op)] (EventRange inRange, EventSink out) { std::transform(inRange.begin(), inRange.end(), out, capturedOp); }; - return Event(std::move(transformFunc), dep); + return Event(std::move(transformFunc), dep); } template @@ -397,7 +398,7 @@ auto Transform(const ReactiveGroup& group, F&& op, const Event& dep, const Si *out++ = capturedPred(v, values ...); }; - return Event(group, std::move(transformFunc), dep, signals ...); + return Event(group, std::move(transformFunc), dep, signals ...); } template @@ -409,7 +410,7 @@ auto Transform(F&& op, const Event& dep, const Signal& ... signals) -> Ev *out++ = capturedPred(v, values ...); }; - return Event(std::move(transformFunc), dep, signals ...); + return Event(std::move(transformFunc), dep, signals ...); } /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -432,32 +433,31 @@ auto Join(const ReactiveGroup& group, const Event& dep1, const Event& .. using REACT_IMPL::EventJoinNode; using REACT_IMPL::PrivateReactiveGroupInterface; using REACT_IMPL::PrivateEventLinkNodeInterface; - using REACT_IMPL::CtorTag; + using REACT_IMPL::PrivateNodeInterface; static_assert(sizeof...(Us) > 0, "Join requires at least 2 inputs."); // If supplied, use merge type, otherwise default to common type. const auto& graphPtr = PrivateReactiveGroupInterface::GraphPtr(group); - return Event, unique>( CtorTag{ }, std::make_shared>( - graphPtr, PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, dep1), PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, deps) ...)); + return PrivateNodeInterface::CreateNodeHelper>, EventJoinNode>( + graphPtr, PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, dep1), PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, deps) ...); } template auto Join(const Event& dep1, const Event& ... deps) -> Event> { using REACT_IMPL::EventJoinNode; - using REACT_IMPL::PrivateNodeInterface; using REACT_IMPL::PrivateEventLinkNodeInterface; - using REACT_IMPL::CtorTag; + using REACT_IMPL::PrivateNodeInterface; static_assert(sizeof...(Us) > 0, "Join requires at least 2 inputs."); // If supplied, use merge type, otherwise default to common type. const auto& graphPtr = PrivateNodeInterface::GraphPtr(dep1); - return Event, unique>( CtorTag{ }, std::make_shared>( - graphPtr, PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, dep1), PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, deps) ...)); + return PrivateNodeInterface::CreateNodeHelper>, EventJoinNode>( + graphPtr, PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, dep1), PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, deps) ...); } /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -500,7 +500,7 @@ struct PrivateEventLinkNodeInterface } else { - return EventLinkBase::CreateLinkNode(targetGraph, dep); + return EventLink::CreateLinkNode(targetGraph, dep); } } }; diff --git a/include/react/Group.h b/include/react/Group.h index 837a2189..050d070f 100644 --- a/include/react/Group.h +++ b/include/react/Group.h @@ -133,6 +133,12 @@ class ReactiveGroup struct PrivateNodeInterface { + // Free functions may have to access the private node constructor (i.e. Merge). + // Instead of making all of them friends, this helper function is used. + template + static auto CreateNodeHelper(TArgs&& ... args) -> decltype(auto) + { return TResult( CtorTag{ }, std::make_shared(std::forward(args) ...)); } + template static auto NodePtr(const TBase& base) -> const std::shared_ptr& { return base.NodePtr(); } diff --git a/include/react/Observer.h b/include/react/Observer.h index 8d2be2a9..c9d33072 100644 --- a/include/react/Observer.h +++ b/include/react/Observer.h @@ -40,37 +40,37 @@ class Observer // Construct signal observer with implicit group template Observer(F&& func, const Signal& ... subjects) : - Observer::Observer(CreateSignalObserverNode(std::forward(func), subjects ...)) + Observer::Observer(REACT_IMPL::CtorTag{ }, CreateSignalObserverNode(std::forward(func), subjects ...)) { } // Construct signal observer with explicit group template Observer(const ReactiveGroup& group, F&& func, const Signal& ... subjects) : - Observer::Observer(CreateSignalObserverNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), std::forward(func), subjects ...)) + Observer::Observer(REACT_IMPL::CtorTag{ }, CreateSignalObserverNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), std::forward(func), subjects ...)) { } // Construct event observer with implicit group template Observer(F&& func, const Event& subject) : - Observer::Observer(CreateEventObserverNode(std::forward(func), subject)) + Observer::Observer(REACT_IMPL::CtorTag{ }, CreateEventObserverNode(std::forward(func), subject)) { } // Construct event observer with explicit group template Observer(const ReactiveGroup& group, F&& func, const Event& subject) : - Observer::Observer(CreateEventObserverNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), std::forward(func), subject)) + Observer::Observer(REACT_IMPL::CtorTag{ }, CreateEventObserverNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), std::forward(func), subject)) { } // Constructed synced event observer with implicit group template Observer(F&& func, const Event& subject, const Signal& ... signals) : - Observer::Observer(CreateSyncedEventObserverNode(std::forward(func), subject, signals ...)) + Observer::Observer(REACT_IMPL::CtorTag{ }, CreateSyncedEventObserverNode(std::forward(func), subject, signals ...)) { } // Constructed synced event observer with explicit group template Observer(const ReactiveGroup& group, F&& func, const Event& subject, const Signal& ... signals) : - Observer::Observer(CreateSyncedEventObserverNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), std::forward(func), subject, signals ...)) + Observer::Observer(REACT_IMPL::CtorTag{ }, CreateSyncedEventObserverNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), std::forward(func), subject, signals ...)) { } void Cancel() @@ -81,7 +81,7 @@ class Observer protected: // Private node ctor - explicit Observer(std::shared_ptr&& nodePtr) : + Observer(REACT_IMPL::CtorTag, std::shared_ptr&& nodePtr) : nodePtr_(std::move(nodePtr)) { } diff --git a/include/react/Signal.h b/include/react/Signal.h index 786710d3..79789527 100644 --- a/include/react/Signal.h +++ b/include/react/Signal.h @@ -202,17 +202,17 @@ class SignalSlot : public Signal // Construct with group + default explicit SignalSlot(const ReactiveGroup& group) : - SignalSlot::SignalSlotBase( REACT_IMPL::CtorTag{ }, CreateSlotNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group)) ) + SignalSlot::Signal( REACT_IMPL::CtorTag{ }, CreateSlotNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group)) ) { } // Construct with group + value SignalSlot(const ReactiveGroup& group, const Signal& input) : - SignalSlot::SignalSlotBase( REACT_IMPL::CtorTag{ }, CreateSlotNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), input) ) + SignalSlot::Signal( REACT_IMPL::CtorTag{ }, CreateSlotNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), input) ) { } // Construct with value explicit SignalSlot(const Signal& input) : - SignalSlot::SignalSlotBase( REACT_IMPL::CtorTag{ }, CreateSlotNode(REACT_IMPL::PrivateNodeInterface::GraphPtr(input), input) ) + SignalSlot::Signal( REACT_IMPL::CtorTag{ }, CreateSlotNode(REACT_IMPL::PrivateNodeInterface::GraphPtr(input), input) ) { } void Set(const Signal& newInput) @@ -308,7 +308,7 @@ struct PrivateSignalLinkNodeInterface } else { - return SignalLinkBase::CreateLinkNode(targetGraph, sig); + return SignalLink::CreateLinkNode(targetGraph, sig); } } }; diff --git a/project/msvc/CppReact.vcxproj b/project/msvc/CppReact.vcxproj index 7ef4b0dc..ead65969 100644 --- a/project/msvc/CppReact.vcxproj +++ b/project/msvc/CppReact.vcxproj @@ -183,7 +183,6 @@ - diff --git a/project/msvc/CppReact.vcxproj.filters b/project/msvc/CppReact.vcxproj.filters index c5384429..76abe5da 100644 --- a/project/msvc/CppReact.vcxproj.filters +++ b/project/msvc/CppReact.vcxproj.filters @@ -122,8 +122,5 @@ Source Files\engine - - Source Files - \ No newline at end of file From fc17e99dc8ff7d1fbe3a66c7ac1ae2465defc321 Mon Sep 17 00:00:00 2001 From: schlangster Date: Wed, 28 Dec 2016 14:01:31 +0100 Subject: [PATCH 44/75] refactor --- benchmarks/src/BenchmarkGrid.h | 4 +- examples/src/BasicAlgorithms.cpp | 12 ++-- examples/src/BasicEvents.cpp | 10 ++-- examples/src/BasicObservers.cpp | 4 +- examples/src/BasicSignals.cpp | 10 ++-- examples/src/BasicSynchronization.cpp | 4 +- examples/src/Main.cpp | 28 ++++----- include/react/API.h | 2 +- include/react/Algorithm.h | 36 ++++++------ include/react/Event.h | 54 +++++++++--------- include/react/Group.h | 79 +++++--------------------- include/react/Observer.h | 12 ++-- include/react/Signal.h | 61 ++++++++------------ include/react/detail/graph/GraphBase.h | 25 ++++---- 14 files changed, 138 insertions(+), 203 deletions(-) diff --git a/benchmarks/src/BenchmarkGrid.h b/benchmarks/src/BenchmarkGrid.h index 6b691cc3..d7ed0bb8 100644 --- a/benchmarks/src/BenchmarkGrid.h +++ b/benchmarks/src/BenchmarkGrid.h @@ -40,7 +40,7 @@ class GridGraphGenerator std::vector widths; - void Generate(const ReactiveGroupBase& group) + void Generate(const GroupBase& group) { assert(inputSignals.size() >= 1); assert(widths.size() >= 1); @@ -132,7 +132,7 @@ struct BenchmarkParams_Grid struct Benchmark_Grid { - double Run(const BenchmarkParams_Grid& params, const ReactiveGroupBase& group) + double Run(const BenchmarkParams_Grid& params, const GroupBase& group) { VarSignal in{ group, 1 }; Signal in2 = in; diff --git a/examples/src/BasicAlgorithms.cpp b/examples/src/BasicAlgorithms.cpp index e804ec81..c2c5d123 100644 --- a/examples/src/BasicAlgorithms.cpp +++ b/examples/src/BasicAlgorithms.cpp @@ -22,7 +22,7 @@ namespace example1 using namespace std; using namespace react; - ReactiveGroup group; + Group group; struct Sensor { @@ -62,7 +62,7 @@ namespace example2 using namespace std; using namespace react; - ReactiveGroup group; + Group group; struct Employee { @@ -96,7 +96,7 @@ namespace example3 using namespace std; using namespace react; - ReactiveGroup group; + Group group; struct Counter { @@ -137,7 +137,7 @@ namespace example4 using namespace std; using namespace react; - ReactiveGroup group; + Group group; struct Sensor { @@ -188,7 +188,7 @@ namespace example5 using namespace std; using namespace react; - ReactiveGroup group; + Group group; enum ECmd { increment, decrement, reset }; @@ -255,7 +255,7 @@ namespace example6 using namespace std; using namespace react; - ReactiveGroup group; + Group group; class Sensor { diff --git a/examples/src/BasicEvents.cpp b/examples/src/BasicEvents.cpp index 97b795c2..da3fa4f2 100644 --- a/examples/src/BasicEvents.cpp +++ b/examples/src/BasicEvents.cpp @@ -22,7 +22,7 @@ namespace example1 // Defines a group. // Each group represents a separate dependency graph. // Reactives from different groups can not be mixed. - ReactiveGroup group; + Group group; // An event source that emits values of type string namespace v1 @@ -87,7 +87,7 @@ namespace example2 using namespace std; using namespace react; - ReactiveGroup group; + Group group; // An event stream that merges both sources EventSource<> leftClick( group ); @@ -124,7 +124,7 @@ namespace example3 using namespace std; using namespace react; - ReactiveGroup group; + Group group; EventSource numbers( group ); @@ -156,7 +156,7 @@ namespace example4 using namespace std; using namespace react; - ReactiveGroup group; + Group group; // Data types enum class Tag { normal, critical }; @@ -206,7 +206,7 @@ namespace example5 using namespace std; using namespace react; - ReactiveGroup group; + Group group; EventSource src( group ); diff --git a/examples/src/BasicObservers.cpp b/examples/src/BasicObservers.cpp index 261e5b88..ad263a2e 100644 --- a/examples/src/BasicObservers.cpp +++ b/examples/src/BasicObservers.cpp @@ -20,7 +20,7 @@ namespace example1 using namespace std; using namespace react; - ReactiveGroup group; + Group group; VarSignal x( group, 1 ); @@ -50,7 +50,7 @@ namespace example2 using namespace std; using namespace react; - ReactiveGroup group; + Group group; EventSource<> trigger( group ); diff --git a/examples/src/BasicSignals.cpp b/examples/src/BasicSignals.cpp index 995872dd..6bd6771d 100644 --- a/examples/src/BasicSignals.cpp +++ b/examples/src/BasicSignals.cpp @@ -29,7 +29,7 @@ namespace example1 // Defines a group. // Each group represents a separate dependency graph. // Reactives from different groups can not be mixed. - ReactiveGroup group; + Group group; // The two words VarSignal firstWord( group, string("Change") ); @@ -64,7 +64,7 @@ namespace example2 using namespace std; using namespace react; - ReactiveGroup group; + Group group; VarSignal x( group, 1 ); @@ -98,7 +98,7 @@ namespace example3 int sumFunc(int a, int b) { return a + b; } - ReactiveGroup group; + Group group; VarSignal a( group, 1 ); VarSignal b( group, 1 ); @@ -136,7 +136,7 @@ namespace example4 using namespace std; using namespace react; - ReactiveGroup group; + Group group; VarSignal> data( group ); @@ -167,7 +167,7 @@ namespace example5 using namespace std; using namespace react; - ReactiveGroup group; + Group group; // Helpers using ExprPairType = pair; diff --git a/examples/src/BasicSynchronization.cpp b/examples/src/BasicSynchronization.cpp index a79f87ce..8eacfa6e 100644 --- a/examples/src/BasicSynchronization.cpp +++ b/examples/src/BasicSynchronization.cpp @@ -21,7 +21,7 @@ namespace example1 using namespace react; using namespace std; - ReactiveGroup<> group; + Group<> group; class Sensor { @@ -31,7 +31,7 @@ namespace example1 Sensor(Sensor&&) = default; Sensor& operator=(Sensor&&) = default; - explicit Sensor(const ReactiveGroup<>& group) : + explicit Sensor(const Group<>& group) : Samples( group ) { } diff --git a/examples/src/Main.cpp b/examples/src/Main.cpp index 653d9d5e..cc5fdc31 100644 --- a/examples/src/Main.cpp +++ b/examples/src/Main.cpp @@ -37,7 +37,7 @@ class GridGraphGenerator std::vector widths; - void Generate(const ReactiveGroup& group) + void Generate(const Group& group) { assert(inputSignals.size() >= 1); assert(widths.size() >= 1); @@ -162,7 +162,7 @@ template T IterFunc2(EventRange evts, T v, T a1, T a2) int main2() { - ReactiveGroup group; + Group group; { // Signals @@ -228,8 +228,8 @@ int main2() // Links { - ReactiveGroup group1; - ReactiveGroup group2; + Group group1; + Group group2; VarSignal s1{ group1, 10 }; VarSignal s2{ group2, 11 }; @@ -244,8 +244,8 @@ int main2() } { - ReactiveGroup group1; - ReactiveGroup group2; + Group group1; + Group group2; VarSignal s1{ group1, 10 }; VarSignal s2{ group2, 11 }; @@ -269,8 +269,8 @@ int main2() } { - ReactiveGroup group1; - ReactiveGroup group2; + Group group1; + Group group2; VarSignal s1{ group1, 10 }; VarSignal s2{ group2, 11 }; @@ -326,7 +326,7 @@ int main2() int main() { - ReactiveGroup group; + Group group; VarSignal in{ group, 1 }; Signal in2 = in; @@ -376,9 +376,9 @@ int main() /*int main2() { - ReactiveGroup group1; - ReactiveGroup group2; - ReactiveGroup group3; + Group group1; + Group group2; + Group group3; VarSignal x{ 0, group1 }; VarSignal y{ 0, group2 }; @@ -420,8 +420,8 @@ int main3() using namespace std; using namespace react; - ReactiveGroup group1; - ReactiveGroup group2; + Group group1; + Group group2; auto sig1 = VarSignal( 10, group1 ); diff --git a/include/react/API.h b/include/react/API.h index dbd0e5df..da892da8 100644 --- a/include/react/API.h +++ b/include/react/API.h @@ -37,7 +37,7 @@ REACT_DEFINE_BITMASK_OPERATORS(TransactionFlags) /////////////////////////////////////////////////////////////////////////////////////////////////// // Groups -class ReactiveGroup; +class Group; // Signals template diff --git a/include/react/Algorithm.h b/include/react/Algorithm.h index f9ab8bb7..e5d6e076 100644 --- a/include/react/Algorithm.h +++ b/include/react/Algorithm.h @@ -27,15 +27,15 @@ /// Hold - Hold the most recent event in a signal /////////////////////////////////////////////////////////////////////////////////////////////////// template -auto Hold(const ReactiveGroup& group, T&& initialValue, const Event& evnt) -> Signal +auto Hold(const Group& group, T&& initialValue, const Event& evnt) -> Signal { using REACT_IMPL::HoldNode; using REACT_IMPL::PrivateEventLinkNodeInterface; - using REACT_IMPL::PrivateReactiveGroupInterface; + using REACT_IMPL::PrivateGroupInterface; using REACT_IMPL::PrivateNodeInterface; using REACT_IMPL::CtorTag; - const auto& graphPtr = PrivateReactiveGroupInterface::GraphPtr(group); + const auto& graphPtr = PrivateGroupInterface::GraphPtr(group); return PrivateNodeInterface::CreateNodeHelper, HoldNode>( graphPtr, std::forward(initialValue), PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, evnt)); @@ -59,14 +59,14 @@ auto Hold(T&& initialValue, const Event& evnt) -> Signal /// Monitor - Emits value changes of target signal /////////////////////////////////////////////////////////////////////////////////////////////////// template -auto Monitor(const ReactiveGroup& group, const Signal& signal) -> Event +auto Monitor(const Group& group, const Signal& signal) -> Event { using REACT_IMPL::MonitorNode; using REACT_IMPL::PrivateSignalLinkNodeInterface; - using REACT_IMPL::PrivateReactiveGroupInterface; + using REACT_IMPL::PrivateGroupInterface; using REACT_IMPL::PrivateNodeInterface; - const auto& graphPtr = PrivateReactiveGroupInterface::GraphPtr(group); + const auto& graphPtr = PrivateGroupInterface::GraphPtr(group); return PrivateNodeInterface::CreateNodeHelper, MonitorNode>( graphPtr, PrivateSignalLinkNodeInterface::GetLocalNodePtr(graphPtr, signal)); @@ -89,13 +89,13 @@ auto Monitor(const Signal& signal) -> Event /// Iterate - Iteratively combines signal value with values from event stream (aka Fold) /////////////////////////////////////////////////////////////////////////////////////////////////// template -auto Iterate(const ReactiveGroup& group, T&& initialValue, F&& func, const Event& evnt) -> Signal +auto Iterate(const Group& group, T&& initialValue, F&& func, const Event& evnt) -> Signal { using REACT_IMPL::IterateNode; using REACT_IMPL::IterateByRefNode; using REACT_IMPL::IsCallableWith; using REACT_IMPL::PrivateEventLinkNodeInterface; - using REACT_IMPL::PrivateReactiveGroupInterface; + using REACT_IMPL::PrivateGroupInterface; using REACT_IMPL::PrivateNodeInterface; using FuncType = typename std::decay::type; @@ -104,7 +104,7 @@ auto Iterate(const ReactiveGroup& group, T&& initialValue, F&& func, const Event IterateNode, IterateByRefNode>::type; - const auto& graphPtr = PrivateReactiveGroupInterface::GraphPtr(group); + const auto& graphPtr = PrivateGroupInterface::GraphPtr(group); return PrivateNodeInterface::CreateNodeHelper, IterNodeType>( graphPtr, std::forward(initialValue), std::forward(func), PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, evnt)); @@ -136,14 +136,14 @@ auto Iterate(T&& initialValue, F&& func, const Event& evnt) -> Signal /// Iterate - Synced /////////////////////////////////////////////////////////////////////////////////////////////////// template -auto Iterate(const ReactiveGroup& group, T&& initialValue, F&& func, const Event& evnt, const Signal& ... signals) -> Signal +auto Iterate(const Group& group, T&& initialValue, F&& func, const Event& evnt, const Signal& ... signals) -> Signal { using REACT_IMPL::SyncedIterateNode; using REACT_IMPL::SyncedIterateByRefNode; using REACT_IMPL::IsCallableWith; using REACT_IMPL::PrivateSignalLinkNodeInterface; using REACT_IMPL::PrivateEventLinkNodeInterface; - using REACT_IMPL::PrivateReactiveGroupInterface; + using REACT_IMPL::PrivateGroupInterface; using REACT_IMPL::PrivateNodeInterface; using FuncType = typename std::decay::type; @@ -152,7 +152,7 @@ auto Iterate(const ReactiveGroup& group, T&& initialValue, F&& func, const Event SyncedIterateNode, SyncedIterateByRefNode>::type; - const auto& graphPtr = PrivateReactiveGroupInterface::GraphPtr(group); + const auto& graphPtr = PrivateGroupInterface::GraphPtr(group); return PrivateNodeInterface::CreateNodeHelper, IterNodeType>( graphPtr, std::forward(initialValue), std::forward(func), @@ -186,15 +186,15 @@ auto Iterate(T&& initialValue, F&& func, const Event& evnt, const Signal& /// Snapshot - Sets signal value to value of other signal when event is received /////////////////////////////////////////////////////////////////////////////////////////////////// template -auto Snapshot(const ReactiveGroup& group, const Signal& signal, const Event& evnt) -> Signal +auto Snapshot(const Group& group, const Signal& signal, const Event& evnt) -> Signal { using REACT_IMPL::SnapshotNode; using REACT_IMPL::PrivateSignalLinkNodeInterface; using REACT_IMPL::PrivateEventLinkNodeInterface;; - using REACT_IMPL::PrivateReactiveGroupInterface; + using REACT_IMPL::PrivateGroupInterface; using REACT_IMPL::PrivateNodeInterface; - const auto& graphPtr = PrivateReactiveGroupInterface::GraphPtr(group); + const auto& graphPtr = PrivateGroupInterface::GraphPtr(group); return PrivateNodeInterface::CreateNodeHelper, SnapshotNode>( graphPtr, PrivateSignalLinkNodeInterface::GetLocalNodePtr(graphPtr, signal), PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, evnt)); @@ -218,15 +218,15 @@ auto Snapshot(const Signal& signal, const Event& evnt) -> Signal /// Pulse - Emits value of target signal when event is received /////////////////////////////////////////////////////////////////////////////////////////////////// template -auto Pulse(const ReactiveGroup& group, const Signal& signal, const Event& evnt) -> Event +auto Pulse(const Group& group, const Signal& signal, const Event& evnt) -> Event { using REACT_IMPL::PulseNode; using REACT_IMPL::PrivateSignalLinkNodeInterface; using REACT_IMPL::PrivateEventLinkNodeInterface;; - using REACT_IMPL::PrivateReactiveGroupInterface; + using REACT_IMPL::PrivateGroupInterface; using REACT_IMPL::PrivateNodeInterface; - const auto& graphPtr = PrivateReactiveGroupInterface::GraphPtr(group); + const auto& graphPtr = PrivateGroupInterface::GraphPtr(group); return PrivateNodeInterface::CreateNodeHelper, PulseNode>( graphPtr, PrivateSignalLinkNodeInterface::GetLocalNodePtr(graphPtr, signal), PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, evnt)); diff --git a/include/react/Event.h b/include/react/Event.h index 9151bc14..58e6ac4d 100644 --- a/include/react/Event.h +++ b/include/react/Event.h @@ -51,8 +51,8 @@ class Event { } template - Event(const ReactiveGroup& group, F&& func, const Event& dep) : - Event::Event( REACT_IMPL::CtorTag{ }, CreateProcessingNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), std::forward(func), dep) ) + Event(const Group& group, F&& func, const Event& dep) : + Event::Event( REACT_IMPL::CtorTag{ }, CreateProcessingNode(REACT_IMPL::PrivateGroupInterface::GraphPtr(group), std::forward(func), dep) ) { } template @@ -61,8 +61,8 @@ class Event { } template - Event(const ReactiveGroup& group, F&& func, const Event& dep, const Signal& ... signals) : - Event::Event( REACT_IMPL::CtorTag{ }, CreateSyncedProcessingNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), std::forward(func), dep, signals ...) ) + Event(const Group& group, F&& func, const Event& dep, const Signal& ... signals) : + Event::Event( REACT_IMPL::CtorTag{ }, CreateSyncedProcessingNode(REACT_IMPL::PrivateGroupInterface::GraphPtr(group), std::forward(func), dep, signals ...) ) { } auto Tokenize() const -> decltype(auto) @@ -136,8 +136,8 @@ class EventSource : public Event EventSource& operator=(EventSource&& other) = default; // Construct event source - explicit EventSource(const ReactiveGroup& group) : - EventSource::Event( REACT_IMPL::CtorTag{ }, CreateSourceNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group)) ) + explicit EventSource(const Group& group) : + EventSource::Event( REACT_IMPL::CtorTag{ }, CreateSourceNode(REACT_IMPL::PrivateGroupInterface::GraphPtr(group)) ) { } void Emit(const E& value) @@ -159,7 +159,7 @@ class EventSource : public Event protected: - auto CreateSourceNode(const std::shared_ptr& graphPtr) -> decltype(auto) + auto CreateSourceNode(const Group& group) -> decltype(auto) { using SrcNodeType = REACT_IMPL::EventSourceNode; return std::make_shared(graphPtr); @@ -197,8 +197,8 @@ class EventSlot : public Event EventSlot& operator=(EventSlot&&) = default; // Construct with value - EventSlot(const ReactiveGroup& group, const Event& input) : - EventSlot::EventSlotBase( REACT_IMPL::CtorTag{ }, CreateSlotNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), input) ) + EventSlot(const Group& group, const Event& input) : + EventSlot::EventSlotBase( REACT_IMPL::CtorTag{ }, CreateSlotNode(group, input) ) { } void Set(const Event& newInput) @@ -208,13 +208,13 @@ class EventSlot : public Event { SetInput(newInput); } protected: - auto CreateSlotNode(const std::shared_ptr& graphPtr, const Event& input) -> decltype(auto) + auto CreateSlotNode(const Group& group, const Event& input) -> decltype(auto) { using REACT_IMPL::PrivateNodeInterface; - using REACT_IMPL::PrivateReactiveGroupInterface; + using REACT_IMPL::PrivateGroupInterface; using SlotNodeType = REACT_IMPL::EventSlotNode; - return std::make_shared(PrivateReactiveGroupInterface::GraphPtr(group), PrivateNodeInterface::NodePtr(input)); + return std::make_shared(group, input); } private: @@ -249,8 +249,8 @@ class EventLink : public Event EventLink& operator=(EventLink&&) = default; // Construct with explicit group - EventLink(const ReactiveGroup& group, const Event& input) : - SignalLink::Signal( REACT_IMPL::CtorTag{ }, CreateLinkNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), input) ) + EventLink(const Group& group, const Event& input) : + SignalLink::Signal( REACT_IMPL::CtorTag{ }, CreateLinkNode(group, input) ) { } // Construct with implicit group @@ -259,13 +259,13 @@ class EventLink : public Event { } protected: - static auto CreateLinkNode(const std::shared_ptr& graphPtr, const Event& input) -> decltype(auto) + static auto CreateLinkNode(const Group& group, const Event& input) -> decltype(auto) { using REACT_IMPL::PrivateNodeInterface; - using REACT_IMPL::PrivateReactiveGroupInterface; + using REACT_IMPL::PrivateGroupInterface; using EventNodeType = REACT_IMPL::EventLinkNode; - auto node = std::make_shared(graphPtr, PrivateNodeInterface::GraphPtr(input), PrivateNodeInterface::NodePtr(input)); + auto node = std::make_shared(group, PrivateNodeInterface::GraphPtr(input), PrivateNodeInterface::NodePtr(input)); node->SetWeakSelfPtr(std::weak_ptr{ node }); return node; } @@ -277,11 +277,11 @@ class EventLink : public Event /// Merge /////////////////////////////////////////////////////////////////////////////////////////////////// template -auto Merge(const ReactiveGroup& group, const Event& dep1, const Event& ... deps) -> decltype(auto) +auto Merge(const Group& group, const Event& dep1, const Event& ... deps) -> decltype(auto) { using REACT_IMPL::EventMergeNode; using REACT_IMPL::PrivateEventLinkNodeInterface; - using REACT_IMPL::PrivateReactiveGroupInterface; + using REACT_IMPL::PrivateGroupInterface; using REACT_IMPL::PrivateNodeInterface; using REACT_IMPL::CtorTag; @@ -293,7 +293,7 @@ auto Merge(const ReactiveGroup& group, const Event& dep1, const Event& . typename std::common_type::type, T>::type; - const auto& graphPtr = PrivateReactiveGroupInterface::GraphPtr(group); + const auto& graphPtr = PrivateGroupInterface::GraphPtr(group); return PrivateNodeInterface::CreateNodeHelper, EventMergeNode>( graphPtr, PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, dep1), PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, deps) ...); @@ -325,7 +325,7 @@ auto Merge(const Event& dep1, const Event& ... deps) -> decltype(auto) /// Filter /////////////////////////////////////////////////////////////////////////////////////////////////// template -auto Filter(const ReactiveGroup& group, F&& pred, const Event& dep) -> Event +auto Filter(const Group& group, F&& pred, const Event& dep) -> Event { auto filterFunc = [capturedPred = std::forward(pred)] (EventRange inRange, EventSink out) { std::copy_if(inRange.begin(), inRange.end(), out, capturedPred); }; @@ -343,7 +343,7 @@ auto Filter(F&& pred, const Event& dep) -> Event } template -auto Filter(const ReactiveGroup& group, F&& pred, const Event& dep, const Signal& ... signals) -> Event +auto Filter(const Group& group, F&& pred, const Event& dep, const Signal& ... signals) -> Event { auto filterFunc = [capturedPred = std::forward(pred)] (EventRange inRange, EventSink out, const Us& ... values) { @@ -372,7 +372,7 @@ auto Filter(F&& pred, const Event& dep, const Signal& ... signals) -> Eve /// Transform /////////////////////////////////////////////////////////////////////////////////////////////////// template -auto Transform(const ReactiveGroup& group, F&& op, const Event& dep) -> Event +auto Transform(const Group& group, F&& op, const Event& dep) -> Event { auto transformFunc = [capturedOp = std::forward(op)] (EventRange inRange, EventSink out) { std::transform(inRange.begin(), inRange.end(), out, capturedOp); }; @@ -390,7 +390,7 @@ auto Transform(F&& op, const Event& dep) -> Event } template -auto Transform(const ReactiveGroup& group, F&& op, const Event& dep, const Signal& ... signals) -> Event +auto Transform(const Group& group, F&& op, const Event& dep, const Signal& ... signals) -> Event { auto transformFunc = [capturedOp = std::forward(pred)] (EventRange inRange, EventSink out, const Vs& ... values) { @@ -428,17 +428,17 @@ auto Flatten(const Signal>& outer) -> Events /// Join /////////////////////////////////////////////////////////////////////////////////////////////////// template -auto Join(const ReactiveGroup& group, const Event& dep1, const Event& ... deps) -> Event> +auto Join(const Group& group, const Event& dep1, const Event& ... deps) -> Event> { using REACT_IMPL::EventJoinNode; - using REACT_IMPL::PrivateReactiveGroupInterface; + using REACT_IMPL::PrivateGroupInterface; using REACT_IMPL::PrivateEventLinkNodeInterface; using REACT_IMPL::PrivateNodeInterface; static_assert(sizeof...(Us) > 0, "Join requires at least 2 inputs."); // If supplied, use merge type, otherwise default to common type. - const auto& graphPtr = PrivateReactiveGroupInterface::GraphPtr(group); + const auto& graphPtr = PrivateGroupInterface::GraphPtr(group); return PrivateNodeInterface::CreateNodeHelper>, EventJoinNode>( graphPtr, PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, dep1), PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, deps) ...); diff --git a/include/react/Group.h b/include/react/Group.h index 050d070f..6e9a645d 100644 --- a/include/react/Group.h +++ b/include/react/Group.h @@ -4,8 +4,8 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -#ifndef REACT_DOMAIN_H_INCLUDED -#define REACT_DOMAIN_H_INCLUDED +#ifndef REACT_GROUP_H_INCLUDED +#define REACT_GROUP_H_INCLUDED #pragma once @@ -21,7 +21,7 @@ /***************************************/ REACT_IMPL_BEGIN /**************************************/ -struct PrivateReactiveGroupInterface; +struct PrivateGroupInterface; struct CtorTag { }; /****************************************/ REACT_IMPL_END /***************************************/ @@ -85,22 +85,22 @@ class TransactionStatus #endif /////////////////////////////////////////////////////////////////////////////////////////////////// -/// ReactiveGroupBase +/// GroupBase /////////////////////////////////////////////////////////////////////////////////////////////////// -class ReactiveGroup +class Group { using GraphType = REACT_IMPL::ReactiveGraph; public: - ReactiveGroup() : + Group() : graphPtr_( std::make_shared() ) { } - ReactiveGroup(const ReactiveGroup&) = default; - ReactiveGroup& operator=(const ReactiveGroup&) = default; + Group(const Group&) = default; + Group& operator=(const Group&) = default; - ReactiveGroup(ReactiveGroup&& other) = default; - ReactiveGroup& operator=(ReactiveGroup&& other) = default; + Group(Group&& other) = default; + Group& operator=(Group&& other) = default; template void DoTransaction(F&& func) @@ -114,7 +114,8 @@ class ReactiveGroup void EnqueueTransaction(TransactionFlags flags, F&& func) { graphPtr_->EnqueueTransaction(flags, std::forward(func)); } -protected: + +public: // Internal auto GraphPtr() -> std::shared_ptr& { return graphPtr_; } @@ -123,62 +124,8 @@ class ReactiveGroup private: std::shared_ptr graphPtr_; - - friend struct REACT_IMPL::PrivateReactiveGroupInterface; }; /******************************************/ REACT_END /******************************************/ -/***************************************/ REACT_IMPL_BEGIN /**************************************/ - -struct PrivateNodeInterface -{ - // Free functions may have to access the private node constructor (i.e. Merge). - // Instead of making all of them friends, this helper function is used. - template - static auto CreateNodeHelper(TArgs&& ... args) -> decltype(auto) - { return TResult( CtorTag{ }, std::make_shared(std::forward(args) ...)); } - - template - static auto NodePtr(const TBase& base) -> const std::shared_ptr& - { return base.NodePtr(); } - - template - static auto NodePtr(TBase& base) -> std::shared_ptr& - { return base.NodePtr(); } - - template - static auto GraphPtr(const TBase& base) -> const std::shared_ptr& - { return base.NodePtr()->GraphPtr(); } - - template - static auto GraphPtr(TBase& base) -> std::shared_ptr& - { return base.NodePtr()->GraphPtr(); } -}; - -struct PrivateReactiveGroupInterface -{ - static auto GraphPtr(const ReactiveGroup& group) -> const std::shared_ptr& - { return group.GraphPtr(); } - - static auto GraphPtr(ReactiveGroup& group) -> std::shared_ptr& - { return group.GraphPtr(); } -}; - -template -static auto GetCheckedGraphPtr(const TBase1& dep1, const TBases& ... deps) -> const std::shared_ptr& -{ - const std::shared_ptr& graphPtr1 = PrivateNodeInterface::GraphPtr(dep1); - - std::initializer_list rawGraphPtrs = { PrivateNodeInterface::GraphPtr(deps).get() ... }; - - bool isSameGraphForAllDeps = std::all_of(rawGraphPtrs.begin(), rawGraphPtrs.end(), [&] (ReactiveGraph* p) { return p == graphPtr1.get(); }); - - REACT_ASSERT(isSameGraphForAllDeps, "All dependencies must belong to the same group."); - - return graphPtr1; -} - -/****************************************/ REACT_IMPL_END /***************************************/ - -#endif // REACT_DOMAIN_H_INCLUDED \ No newline at end of file +#endif // REACT_GROUP_H_INCLUDED \ No newline at end of file diff --git a/include/react/Observer.h b/include/react/Observer.h index c9d33072..0d2a82e0 100644 --- a/include/react/Observer.h +++ b/include/react/Observer.h @@ -45,8 +45,8 @@ class Observer // Construct signal observer with explicit group template - Observer(const ReactiveGroup& group, F&& func, const Signal& ... subjects) : - Observer::Observer(REACT_IMPL::CtorTag{ }, CreateSignalObserverNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), std::forward(func), subjects ...)) + Observer(const Group& group, F&& func, const Signal& ... subjects) : + Observer::Observer(REACT_IMPL::CtorTag{ }, CreateSignalObserverNode(REACT_IMPL::PrivateGroupInterface::GraphPtr(group), std::forward(func), subjects ...)) { } // Construct event observer with implicit group @@ -57,8 +57,8 @@ class Observer // Construct event observer with explicit group template - Observer(const ReactiveGroup& group, F&& func, const Event& subject) : - Observer::Observer(REACT_IMPL::CtorTag{ }, CreateEventObserverNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), std::forward(func), subject)) + Observer(const Group& group, F&& func, const Event& subject) : + Observer::Observer(REACT_IMPL::CtorTag{ }, CreateEventObserverNode(REACT_IMPL::PrivateGroupInterface::GraphPtr(group), std::forward(func), subject)) { } // Constructed synced event observer with implicit group @@ -69,8 +69,8 @@ class Observer // Constructed synced event observer with explicit group template - Observer(const ReactiveGroup& group, F&& func, const Event& subject, const Signal& ... signals) : - Observer::Observer(REACT_IMPL::CtorTag{ }, CreateSyncedEventObserverNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), std::forward(func), subject, signals ...)) + Observer(const Group& group, F&& func, const Event& subject, const Signal& ... signals) : + Observer::Observer(REACT_IMPL::CtorTag{ }, CreateSyncedEventObserverNode(REACT_IMPL::PrivateGroupInterface::GraphPtr(group), std::forward(func), subject, signals ...)) { } void Cancel() diff --git a/include/react/Signal.h b/include/react/Signal.h index 79789527..bc607a9f 100644 --- a/include/react/Signal.h +++ b/include/react/Signal.h @@ -42,24 +42,16 @@ class Signal using NodeType = REACT_IMPL::SignalNode; public: - const S& Value() const - { return nodePtr_->Value(); } - - // Empty signal - Signal() = default; - - // Copy ctor & assignment Signal(const Signal&) = default; Signal& operator=(const Signal&) = default; - // Move ctor & assignment Signal(Signal&&) = default; Signal& operator=(Signal&&) = default; // Construct func signal with explicit group template - explicit Signal(const ReactiveGroup& group, F&& func, const Signal& dep1, const Signal& ... deps) : - Signal::Signal( REACT_IMPL::CtorTag{ }, CreateFuncNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), std::forward(func), dep1, deps ...) ) + explicit Signal(const Group& group, F&& func, const Signal& dep1, const Signal& ... deps) : + Signal::Signal( REACT_IMPL::CtorTag{ }, CreateFuncNode(REACT_IMPL::PrivateGroupInterface::GraphPtr(group), std::forward(func), dep1, deps ...) ) { } // Construct func signal with implicit group @@ -68,7 +60,10 @@ class Signal Signal::Signal( REACT_IMPL::CtorTag{ }, CreateFuncNode(REACT_IMPL::PrivateNodeInterface::GraphPtr(dep1), std::forward(func), dep1, deps ...) ) { } -protected: + const Group& GetGroup() const + { return nodePtr_->GetGroup(); } + +public: // Internal // Private node ctor Signal(REACT_IMPL::CtorTag, std::shared_ptr&& nodePtr) : nodePtr_( std::move(nodePtr) ) @@ -80,6 +75,7 @@ class Signal auto NodePtr() const -> const std::shared_ptr& { return nodePtr_; } +protected: template auto CreateFuncNode(const std::shared_ptr& graphPtr, F&& func, const Signal& dep1, const Signal& ... deps) -> decltype(auto) { @@ -94,11 +90,8 @@ class Signal private: std::shared_ptr nodePtr_; - - friend struct REACT_IMPL::PrivateNodeInterface; }; - /////////////////////////////////////////////////////////////////////////////////////////////////// /// VarSignal /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -106,10 +99,6 @@ template class VarSignal : public Signal { public: - using Signal::Signal; - - VarSignal() = default; - VarSignal(const VarSignal&) = default; VarSignal& operator=(const VarSignal&) = default; @@ -117,14 +106,14 @@ class VarSignal : public Signal VarSignal& operator=(VarSignal&&) = default; // Construct with group + default - explicit VarSignal(const ReactiveGroup& group) : - VarSignal::Signal( REACT_IMPL::CtorTag{ }, CreateVarNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group)) ) + explicit VarSignal(const Group& group) : + VarSignal::Signal( REACT_IMPL::CtorTag{ }, CreateVarNode(group) ) { } // Construct with group + value template - VarSignal(const ReactiveGroup& group, T&& value) : - VarSignal::Signal( REACT_IMPL::CtorTag{ }, CreateVarNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), std::forward(value)) ) + VarSignal(const Group& group, T&& value) : + VarSignal::Signal( REACT_IMPL::CtorTag{ }, CreateVarNode(group, std::forward(value)) ) { } void Set(const S& newValue) @@ -144,14 +133,14 @@ class VarSignal : public Signal { ModifyValue(func); } protected: - static auto CreateVarNode(const std::shared_ptr& graphPtr) -> decltype(auto) + static auto CreateVarNode(const Group& group) -> decltype(auto) { using VarNodeType = REACT_IMPL::VarSignalNode; return std::make_shared(graphPtr); } template - static auto CreateVarNode(const std::shared_ptr& graphPtr, T&& value) -> decltype(auto) + static auto CreateVarNode(const Group& group, T&& value) -> decltype(auto) { using VarNodeType = REACT_IMPL::VarSignalNode; return std::make_shared(graphPtr, std::forward(value)); @@ -162,7 +151,6 @@ class VarSignal : public Signal void SetValue(T&& newValue) { using REACT_IMPL::NodeId; - using REACT_IMPL::ReactiveGraph; using VarNodeType = REACT_IMPL::VarSignalNode; VarNodeType* castedPtr = static_cast(this->NodePtr().get()); @@ -176,7 +164,6 @@ class VarSignal : public Signal void ModifyValue(const F& func) { using REACT_IMPL::NodeId; - using REACT_IMPL::ReactiveGraph; using VarNodeType = REACT_IMPL::VarSignalNode; VarNodeType* castedPtr = static_cast(this->NodePtr().get()); @@ -201,13 +188,13 @@ class SignalSlot : public Signal SignalSlot& operator=(SignalSlot&&) = default; // Construct with group + default - explicit SignalSlot(const ReactiveGroup& group) : - SignalSlot::Signal( REACT_IMPL::CtorTag{ }, CreateSlotNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group)) ) + explicit SignalSlot(const Group& group) : + SignalSlot::Signal( REACT_IMPL::CtorTag{ }, CreateSlotNode(REACT_IMPL::PrivateGroupInterface::GraphPtr(group)) ) { } // Construct with group + value - SignalSlot(const ReactiveGroup& group, const Signal& input) : - SignalSlot::Signal( REACT_IMPL::CtorTag{ }, CreateSlotNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), input) ) + SignalSlot(const Group& group, const Signal& input) : + SignalSlot::Signal( REACT_IMPL::CtorTag{ }, CreateSlotNode(REACT_IMPL::PrivateGroupInterface::GraphPtr(group), input) ) { } // Construct with value @@ -222,7 +209,7 @@ class SignalSlot : public Signal { SetInput(newInput); } protected: - static auto CreateSlotNode(const std::shared_ptr& graphPtr, const Signal& input) -> decltype(auto) + static auto CreateSlotNode(const Group& group, const Signal& input) -> decltype(auto) { using REACT_IMPL::PrivateNodeInterface; using SlotNodeType = REACT_IMPL::SignalSlotNode; @@ -252,8 +239,6 @@ template class SignalLink : public Signal { public: - SignalLink() = default; - SignalLink(const SignalLink&) = default; SignalLink& operator=(const SignalLink&) = default; @@ -261,20 +246,20 @@ class SignalLink : public Signal SignalLink& operator=(SignalLink&&) = default; // Construct with explicit group - SignalLink(const ReactiveGroup& group, const Signal& input) : - SignalLink::Signal( REACT_IMPL::CtorTag{ }, CreateLinkNode(REACT_IMPL::PrivateReactiveGroupInterface::GraphPtr(group), input) ) + SignalLink(const Group& group, const Signal& input) : + SignalLink::Signal( REACT_IMPL::CtorTag{ }, CreateLinkNode(group, input) ) { } // Construct with implicit group explicit SignalLink(const Signal& input) : - SignalLink::Signal( REACT_IMPL::CtorTag{ }, CreateLinkNode(REACT_IMPL::PrivateNodeInterface::GraphPtr(input), input) ) + SignalLink::Signal( REACT_IMPL::CtorTag{ }, CreateLinkNode(input.GetGroup(), input) ) { } protected: - static auto CreateLinkNode(const std::shared_ptr& graphPtr, const Signal& input) -> decltype(auto) + static auto CreateLinkNode(const Group& group, const Signal& input) -> decltype(auto) { using REACT_IMPL::PrivateNodeInterface; - using REACT_IMPL::PrivateReactiveGroupInterface; + using REACT_IMPL::PrivateGroupInterface; using LinkNodeType = REACT_IMPL::SignalLinkNode; auto node = std::make_shared(graphPtr, PrivateNodeInterface::GraphPtr(input), PrivateNodeInterface::NodePtr(input)); diff --git a/include/react/detail/graph/GraphBase.h b/include/react/detail/graph/GraphBase.h index d39809bb..3305ca40 100644 --- a/include/react/detail/graph/GraphBase.h +++ b/include/react/detail/graph/GraphBase.h @@ -29,8 +29,8 @@ class ReactiveGraph; class NodeBase : public IReactiveNode { public: - NodeBase(const std::shared_ptr& graphPtr) : - graphPtr_( graphPtr ) + NodeBase(const Group& group) : + group_( group ) { } NodeBase(const NodeBase&) = delete; @@ -58,35 +58,38 @@ class NodeBase : public IReactiveNode NodeId GetNodeId() const { return nodeId_; } + const Group& GetGroup() const + { return group_; } + auto GraphPtr() const -> const std::shared_ptr& - { return graphPtr_; } + { return GroupInternals::GraphPtr(group_); } auto GraphPtr() -> std::shared_ptr& - { return graphPtr_; } + { return GroupInternals::GraphPtr(group_); } protected: void RegisterMe(NodeCategory category = NodeCategory::normal) - { nodeId_ = graphPtr_->RegisterNode(this, category); } + { nodeId_ = GraphPtr()->RegisterNode(this, category); } void UnregisterMe() - { graphPtr_->UnregisterNode(nodeId_); } + { GraphPtr()->UnregisterNode(nodeId_); } void AttachToMe(NodeId otherNodeId) - { graphPtr_->OnNodeAttach(nodeId_, otherNodeId); } + { GraphPtr()->OnNodeAttach(nodeId_, otherNodeId); } void DetachFromMe(NodeId otherNodeId) - { graphPtr_->OnNodeDetach(nodeId_, otherNodeId); } + { GraphPtr()->OnNodeDetach(nodeId_, otherNodeId); } void DynamicAttachToMe(NodeId otherNodeId, TurnId turnId) - { graphPtr_->OnDynamicNodeAttach(nodeId_, otherNodeId, turnId); } + { GraphPtr()->OnDynamicNodeAttach(nodeId_, otherNodeId, turnId); } void DynamicDetachFromMe(NodeId otherNodeId, TurnId turnId) - { graphPtr_->OnDynamicNodeDetach(nodeId_, otherNodeId, turnId); } + { GraphPtr()->OnDynamicNodeDetach(nodeId_, otherNodeId, turnId); } private: NodeId nodeId_; - std::shared_ptr graphPtr_; + Group group_; }; /****************************************/ REACT_IMPL_END /***************************************/ From 1116f3a55ad263ebe21a48bbc9fc34e2662de7ed Mon Sep 17 00:00:00 2001 From: schlangster Date: Wed, 28 Dec 2016 14:46:47 +0100 Subject: [PATCH 45/75] progress --- include/react/Event.h | 21 ++++-------------- include/react/Observer.h | 46 +++++++++++++++------------------------- 2 files changed, 21 insertions(+), 46 deletions(-) diff --git a/include/react/Event.h b/include/react/Event.h index 58e6ac4d..d0dec01b 100644 --- a/include/react/Event.h +++ b/include/react/Event.h @@ -37,8 +37,6 @@ class Event using NodeType = REACT_IMPL::EventStreamNode; public: - Event() = default; - Event(const Event&) = default; Event& operator=(const Event&) = default; @@ -52,7 +50,7 @@ class Event template Event(const Group& group, F&& func, const Event& dep) : - Event::Event( REACT_IMPL::CtorTag{ }, CreateProcessingNode(REACT_IMPL::PrivateGroupInterface::GraphPtr(group), std::forward(func), dep) ) + Event::Event( REACT_IMPL::CtorTag{ }, CreateProcessingNode(group, std::forward(func), dep) ) { } template @@ -62,7 +60,7 @@ class Event template Event(const Group& group, F&& func, const Event& dep, const Signal& ... signals) : - Event::Event( REACT_IMPL::CtorTag{ }, CreateSyncedProcessingNode(REACT_IMPL::PrivateGroupInterface::GraphPtr(group), std::forward(func), dep, signals ...) ) + Event::Event( REACT_IMPL::CtorTag{ }, CreateSyncedProcessingNode(group, std::forward(func), dep, signals ...) ) { } auto Tokenize() const -> decltype(auto) @@ -127,8 +125,6 @@ template class EventSource : public Event { public: - EventSource() = default; - EventSource(const EventSource&) = default; EventSource& operator=(const EventSource&) = default; @@ -137,7 +133,7 @@ class EventSource : public Event // Construct event source explicit EventSource(const Group& group) : - EventSource::Event( REACT_IMPL::CtorTag{ }, CreateSourceNode(REACT_IMPL::PrivateGroupInterface::GraphPtr(group)) ) + EventSource::Event( REACT_IMPL::CtorTag{ }, CreateSourceNode(group) ) { } void Emit(const E& value) @@ -157,12 +153,10 @@ class EventSource : public Event { EmitValue(std::move(value)); return *this; } protected: - - auto CreateSourceNode(const Group& group) -> decltype(auto) { using SrcNodeType = REACT_IMPL::EventSourceNode; - return std::make_shared(graphPtr); + return std::make_shared(group); } private: @@ -188,8 +182,6 @@ template class EventSlot : public Event { public: - EventSlot() = default; - EventSlot(const EventSlot&) = default; EventSlot& operator=(const EventSlot&) = default; @@ -210,8 +202,6 @@ class EventSlot : public Event protected: auto CreateSlotNode(const Group& group, const Event& input) -> decltype(auto) { - using REACT_IMPL::PrivateNodeInterface; - using REACT_IMPL::PrivateGroupInterface; using SlotNodeType = REACT_IMPL::EventSlotNode; return std::make_shared(group, input); @@ -220,7 +210,6 @@ class EventSlot : public Event private: void SetInput(const Event& newInput) { - using REACT_IMPL::PrivateNodeInterface; using REACT_IMPL::NodeId; using REACT_IMPL::ReactiveGraph; using SlotNodeType = REACT_IMPL::EventSlotNode; @@ -240,8 +229,6 @@ template class EventLink : public Event { public: - EventLink() = default; - EventLink(const EventLink&) = default; EventLink& operator=(const EventLink&) = default; diff --git a/include/react/Observer.h b/include/react/Observer.h index 0d2a82e0..b0b64c8e 100644 --- a/include/react/Observer.h +++ b/include/react/Observer.h @@ -29,8 +29,6 @@ class Observer using NodeType = REACT_IMPL::ObserverNode; public: - Observer() = default; - Observer(const Observer&) = default; Observer& operator=(const Observer&) = default; @@ -41,45 +39,39 @@ class Observer template Observer(F&& func, const Signal& ... subjects) : Observer::Observer(REACT_IMPL::CtorTag{ }, CreateSignalObserverNode(std::forward(func), subjects ...)) - { } + { } // Construct signal observer with explicit group template Observer(const Group& group, F&& func, const Signal& ... subjects) : - Observer::Observer(REACT_IMPL::CtorTag{ }, CreateSignalObserverNode(REACT_IMPL::PrivateGroupInterface::GraphPtr(group), std::forward(func), subjects ...)) - { } + Observer::Observer(REACT_IMPL::CtorTag{ }, CreateSignalObserverNode(group, std::forward(func), subjects ...)) + { } // Construct event observer with implicit group template Observer(F&& func, const Event& subject) : Observer::Observer(REACT_IMPL::CtorTag{ }, CreateEventObserverNode(std::forward(func), subject)) - { } + { } // Construct event observer with explicit group template Observer(const Group& group, F&& func, const Event& subject) : - Observer::Observer(REACT_IMPL::CtorTag{ }, CreateEventObserverNode(REACT_IMPL::PrivateGroupInterface::GraphPtr(group), std::forward(func), subject)) - { } + Observer::Observer(REACT_IMPL::CtorTag{ }, CreateEventObserverNode(group, std::forward(func), subject)) + { } // Constructed synced event observer with implicit group template Observer(F&& func, const Event& subject, const Signal& ... signals) : Observer::Observer(REACT_IMPL::CtorTag{ }, CreateSyncedEventObserverNode(std::forward(func), subject, signals ...)) - { } + { } // Constructed synced event observer with explicit group template Observer(const Group& group, F&& func, const Event& subject, const Signal& ... signals) : - Observer::Observer(REACT_IMPL::CtorTag{ }, CreateSyncedEventObserverNode(REACT_IMPL::PrivateGroupInterface::GraphPtr(group), std::forward(func), subject, signals ...)) - { } - - void Cancel() - { nodePtr_.reset(); } - - bool IsCancelled() const - { return nodePtr_ != nullptr; } + Observer::Observer(REACT_IMPL::CtorTag{ }, CreateSyncedEventObserverNode(group, std::forward(func), subject, signals ...)) + { } -protected: +public: //Internal // Private node ctor Observer(REACT_IMPL::CtorTag, std::shared_ptr&& nodePtr) : nodePtr_(std::move(nodePtr)) @@ -91,14 +83,15 @@ class Observer auto NodePtr() const -> const std::shared_ptr& { return nodePtr_; } +protected: template - auto CreateSignalObserverNode(const std::shared_ptr& graphPtr, F&& func, const Signal& dep1, const Signal& ... deps) -> decltype(auto) + auto CreateSignalObserverNode(const Group& group, F&& func, const Signal& dep1, const Signal& ... deps) -> decltype(auto) { using REACT_IMPL::PrivateSignalLinkNodeInterface; using ObsNodeType = REACT_IMPL::SignalObserverNode::type, T1, Ts ...>; return std::make_shared( - graphPtr, + group, std::forward(func), PrivateSignalLinkNodeInterface::GetLocalNodePtr(graphPtr, dep1), PrivateSignalLinkNodeInterface::GetLocalNodePtr(graphPtr, deps) ...); } @@ -106,28 +99,26 @@ class Observer template auto CreateSignalObserverNode(F&& func, const Signal& dep1, const Signal& ... deps) -> decltype(auto) { - using REACT_IMPL::PrivateNodeInterface; return CreateSignalObserverNode(PrivateNodeInterface::GraphPtr(dep1), std::forward(func), dep1, deps ...); } template - auto CreateEventObserverNode(const std::shared_ptr& graphPtr, F&& func, const Event& dep) -> decltype(auto) + auto CreateEventObserverNode(const Group& group, F&& func, const Event& dep) -> decltype(auto) { using REACT_IMPL::PrivateEventLinkNodeInterface; using ObsNodeType = REACT_IMPL::EventObserverNode::type, T>; - return std::make_shared(graphPtr, std::forward(func), PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, dep)); + return std::make_shared(group, std::forward(func), PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, dep)); } template auto CreateEventObserverNode(F&& func, const Event& dep) -> decltype(auto) { - using REACT_IMPL::PrivateNodeInterface; return CreateEventObserverNode(PrivateNodeInterface::GraphPtr(dep), std::forward(func), dep); } template - auto CreateSyncedEventObserverNode(const std::shared_ptr& graphPtr, F&& func, const Event& dep, const Signal& ... syncs) -> decltype(auto) + auto CreateSyncedEventObserverNode(const Group& group, F&& func, const Event& dep, const Signal& ... syncs) -> decltype(auto) { using REACT_IMPL::PrivateEventLinkNodeInterface; using REACT_IMPL::PrivateSignalLinkNodeInterface; @@ -140,14 +131,11 @@ class Observer template auto CreateSyncedEventObserverNode(F&& func, const Event& dep, const Signal& ... syncs) -> decltype(auto) { - using REACT_IMPL::PrivateNodeInterface; return CreateSyncedEventObserverNode(PrivateNodeInterface::GraphPtr(dep), std::forward(func), dep, syncs ...); } private: - std::shared_ptr nodePtr_; - - friend struct REACT_IMPL::PrivateNodeInterface; + std::shared_ptr nodePtr_;s }; /******************************************/ REACT_END /******************************************/ From d7c2e2dde4439c0196d8d141b1c5b3f947008bba Mon Sep 17 00:00:00 2001 From: schlangster Date: Sun, 1 Jan 2017 23:49:19 +0100 Subject: [PATCH 46/75] wip refactoring --- include/react/Algorithm.h | 147 +---------- include/react/Event.h | 266 +++++++++----------- include/react/Group.h | 62 +++-- include/react/Observer.h | 80 ++---- include/react/Signal.h | 217 ++++++++-------- include/react/detail/Defs.h | 18 +- include/react/detail/graph/AlgorithmNodes.h | 54 ++-- include/react/detail/graph/EventNodes.h | 92 +++---- include/react/detail/graph/GraphBase.h | 27 +- include/react/detail/graph/ObserverNodes.h | 51 ++-- include/react/detail/graph/SignalNodes.h | 99 ++++---- 11 files changed, 476 insertions(+), 637 deletions(-) diff --git a/include/react/Algorithm.h b/include/react/Algorithm.h index e5d6e076..babc4c8b 100644 --- a/include/react/Algorithm.h +++ b/include/react/Algorithm.h @@ -30,30 +30,12 @@ template auto Hold(const Group& group, T&& initialValue, const Event& evnt) -> Signal { using REACT_IMPL::HoldNode; - using REACT_IMPL::PrivateEventLinkNodeInterface; - using REACT_IMPL::PrivateGroupInterface; - using REACT_IMPL::PrivateNodeInterface; - using REACT_IMPL::CtorTag; - - const auto& graphPtr = PrivateGroupInterface::GraphPtr(group); - - return PrivateNodeInterface::CreateNodeHelper, HoldNode>( - graphPtr, std::forward(initialValue), PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, evnt)); + return Signal::CreateWithNode>(group, std::forward(initialValue), SameGroupOrLink(group, evnt)); } template auto Hold(T&& initialValue, const Event& evnt) -> Signal -{ - using REACT_IMPL::HoldNode; - using REACT_IMPL::PrivateEventLinkNodeInterface; - using REACT_IMPL::PrivateNodeInterface; - using REACT_IMPL::CtorTag; - - const auto& graphPtr = PrivateNodeInterface::GraphPtr(evnt); - - return PrivateNodeInterface::CreateNodeHelper, HoldNode>( - graphPtr, std::forward(initialValue), PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, evnt)); -} + { return Hold(evnt.GetGroup(), std::forward(initialValue), evnt); } /////////////////////////////////////////////////////////////////////////////////////////////////// /// Monitor - Emits value changes of target signal @@ -62,28 +44,12 @@ template auto Monitor(const Group& group, const Signal& signal) -> Event { using REACT_IMPL::MonitorNode; - using REACT_IMPL::PrivateSignalLinkNodeInterface; - using REACT_IMPL::PrivateGroupInterface; - using REACT_IMPL::PrivateNodeInterface; - - const auto& graphPtr = PrivateGroupInterface::GraphPtr(group); - - return PrivateNodeInterface::CreateNodeHelper, MonitorNode>( - graphPtr, PrivateSignalLinkNodeInterface::GetLocalNodePtr(graphPtr, signal)); + return Event::CreateWithNode>(group, SameGroupOrLink(group, signal)); } template auto Monitor(const Signal& signal) -> Event -{ - using REACT_IMPL::MonitorNode; - using REACT_IMPL::PrivateSignalLinkNodeInterface; - using REACT_IMPL::PrivateNodeInterface; - - const auto& graphPtr = PrivateNodeInterface::GraphPtr(signal); - - return PrivateNodeInterface::CreateNodeHelper, MonitorNode>( - graphPtr, PrivateSignalLinkNodeInterface::GetLocalNodePtr(graphPtr, signal)); -} + { return Monitor(signal.GetGroup(), signal); } /////////////////////////////////////////////////////////////////////////////////////////////////// /// Iterate - Iteratively combines signal value with values from event stream (aka Fold) @@ -94,9 +60,6 @@ auto Iterate(const Group& group, T&& initialValue, F&& func, const Event& evn using REACT_IMPL::IterateNode; using REACT_IMPL::IterateByRefNode; using REACT_IMPL::IsCallableWith; - using REACT_IMPL::PrivateEventLinkNodeInterface; - using REACT_IMPL::PrivateGroupInterface; - using REACT_IMPL::PrivateNodeInterface; using FuncType = typename std::decay::type; using IterNodeType = typename std::conditional< @@ -104,33 +67,12 @@ auto Iterate(const Group& group, T&& initialValue, F&& func, const Event& evn IterateNode, IterateByRefNode>::type; - const auto& graphPtr = PrivateGroupInterface::GraphPtr(group); - - return PrivateNodeInterface::CreateNodeHelper, IterNodeType>( - graphPtr, std::forward(initialValue), std::forward(func), PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, evnt)); + return Signal::CreateWithNode(group, std::forward(initialValue), std::forward(func), SameGroupOrLink(group, evnt)); } template auto Iterate(T&& initialValue, F&& func, const Event& evnt) -> Signal -{ - using REACT_IMPL::IterateNode; - using REACT_IMPL::IterateByRefNode; - using REACT_IMPL::IsCallableWith; - using REACT_IMPL::PrivateEventLinkNodeInterface; - using REACT_IMPL::PrivateNodeInterface; - using REACT_IMPL::CtorTag; - - using FuncType = typename std::decay::type; - using IterNodeType = typename std::conditional< - IsCallableWith,S>::value, - IterateNode, - IterateByRefNode>::type; - - const auto& graphPtr = PrivateNodeInterface::GraphPtr(evnt); - - return PrivateNodeInterface::CreateNodeHelper, IterNodeType>( - graphPtr, std::forward(initialValue), std::forward(func), PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, evnt)); -} + { return Iterate(evnt.GetGroup(), std::forward(initialValue), std::forward(func), evnt); } /////////////////////////////////////////////////////////////////////////////////////////////////// /// Iterate - Synced @@ -141,10 +83,6 @@ auto Iterate(const Group& group, T&& initialValue, F&& func, const Event& evn using REACT_IMPL::SyncedIterateNode; using REACT_IMPL::SyncedIterateByRefNode; using REACT_IMPL::IsCallableWith; - using REACT_IMPL::PrivateSignalLinkNodeInterface; - using REACT_IMPL::PrivateEventLinkNodeInterface; - using REACT_IMPL::PrivateGroupInterface; - using REACT_IMPL::PrivateNodeInterface; using FuncType = typename std::decay::type; using IterNodeType = typename std::conditional< @@ -152,35 +90,13 @@ auto Iterate(const Group& group, T&& initialValue, F&& func, const Event& evn SyncedIterateNode, SyncedIterateByRefNode>::type; - const auto& graphPtr = PrivateGroupInterface::GraphPtr(group); - - return PrivateNodeInterface::CreateNodeHelper, IterNodeType>( - graphPtr, std::forward(initialValue), std::forward(func), - PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, evnt), PrivateSignalLinkNodeInterface::GetLocalNodePtr(graphPtr, signals) ...); + return Signal::CreateWithNode( + group, std::forward(initialValue), std::forward(func), SameGroupOrLink(group, evnt), SameGroupOrLink(group, signals) ...); } template auto Iterate(T&& initialValue, F&& func, const Event& evnt, const Signal& ... signals) -> Signal -{ - using REACT_IMPL::SyncedIterateNode; - using REACT_IMPL::SyncedIterateByRefNode; - using REACT_IMPL::IsCallableWith; - using REACT_IMPL::PrivateSignalLinkNodeInterface; - using REACT_IMPL::PrivateEventLinkNodeInterface;; - using REACT_IMPL::PrivateNodeInterface; - - using FuncType = typename std::decay::type; - using IterNodeType = typename std::conditional< - IsCallableWith, S, Us ...>::value, - SyncedIterateNode, - SyncedIterateByRefNode>::type; - - const auto& graphPtr = PrivateNodeInterface::GraphPtr(evnt); - - return PrivateNodeInterface::CreateNodeHelper, IterNodeType>( - graphPtr, std::forward(initialValue), std::forward(func), - PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, evnt), PrivateSignalLinkNodeInterface::GetLocalNodePtr(graphPtr, signals) ...); -} + { return Iterate(evnt.GetGroup(), std::forward(initialValue), std::forward(func), evnt, signals ...); } /////////////////////////////////////////////////////////////////////////////////////////////////// /// Snapshot - Sets signal value to value of other signal when event is received @@ -189,30 +105,12 @@ template auto Snapshot(const Group& group, const Signal& signal, const Event& evnt) -> Signal { using REACT_IMPL::SnapshotNode; - using REACT_IMPL::PrivateSignalLinkNodeInterface; - using REACT_IMPL::PrivateEventLinkNodeInterface;; - using REACT_IMPL::PrivateGroupInterface; - using REACT_IMPL::PrivateNodeInterface; - - const auto& graphPtr = PrivateGroupInterface::GraphPtr(group); - - return PrivateNodeInterface::CreateNodeHelper, SnapshotNode>( - graphPtr, PrivateSignalLinkNodeInterface::GetLocalNodePtr(graphPtr, signal), PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, evnt)); + return Signal::CreateWithNode>(group, SameGroupOrLink(group, signal), SameGroupOrLink(group, evnt)); } template auto Snapshot(const Signal& signal, const Event& evnt) -> Signal -{ - using REACT_IMPL::SnapshotNode; - using REACT_IMPL::PrivateSignalLinkNodeInterface; - using REACT_IMPL::PrivateEventLinkNodeInterface;; - using REACT_IMPL::PrivateNodeInterface; - - const auto& graphPtr = PrivateNodeInterface::GraphPtr(signal); - - return PrivateNodeInterface::CreateNodeHelper, SnapshotNode>( - graphPtr, PrivateSignalLinkNodeInterface::GetLocalNodePtr(graphPtr, signal), PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, evnt)); -} + { return Snapshot(signal.GetGroup(), signal, evnt); } /////////////////////////////////////////////////////////////////////////////////////////////////// /// Pulse - Emits value of target signal when event is received @@ -221,31 +119,12 @@ template auto Pulse(const Group& group, const Signal& signal, const Event& evnt) -> Event { using REACT_IMPL::PulseNode; - using REACT_IMPL::PrivateSignalLinkNodeInterface; - using REACT_IMPL::PrivateEventLinkNodeInterface;; - using REACT_IMPL::PrivateGroupInterface; - using REACT_IMPL::PrivateNodeInterface; - - const auto& graphPtr = PrivateGroupInterface::GraphPtr(group); - - return PrivateNodeInterface::CreateNodeHelper, PulseNode>( - graphPtr, PrivateSignalLinkNodeInterface::GetLocalNodePtr(graphPtr, signal), PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, evnt)); + return Event::CreateWithNode>(group, SameGroupOrLink(group, signal), SameGroupOrLink(group, evnt)); } template auto Pulse(const Signal& signal, const Event& evnt) -> Event -{ - using REACT_IMPL::PulseNode; - using REACT_IMPL::PrivateSignalLinkNodeInterface; - using REACT_IMPL::PrivateEventLinkNodeInterface;; - using REACT_IMPL::PrivateNodeInterface; - using REACT_IMPL::CtorTag; - - const auto& graphPtr = PrivateNodeInterface::GraphPtr(signal); - - return PrivateNodeInterface::CreateNodeHelper, PulseNode>( - graphPtr, PrivateSignalLinkNodeInterface::GetLocalNodePtr(graphPtr, signal), PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, evnt)); -} + { return Pulse(signal.GetGroup(), signal, evnt); } /******************************************/ REACT_END /******************************************/ diff --git a/include/react/Event.h b/include/react/Event.h index d0dec01b..e4d2a987 100644 --- a/include/react/Event.h +++ b/include/react/Event.h @@ -21,7 +21,48 @@ /***************************************/ REACT_IMPL_BEGIN /**************************************/ -struct PrivateEventLinkNodeInterface; +template +class EventInternals +{ +protected: + using NodeType = EventStreamNode; + using StorageType = typename NodeType::StorageType; + +public: + EventInternals(const EventInternals&) = default; + EventInternals& operator=(const EventInternals&) = default; + + EventInternals(EventInternals&&) = default; + EventInternals& operator=(EventInternals&&) = default; + + EventInternals(std::shared_ptr&& nodePtr) : + nodePtr_( std::move(nodePtr) ) + { } + + auto GetNodePtr() -> std::shared_ptr& + { return nodePtr_; } + + auto GetNodePtr() const -> const std::shared_ptr& + { return nodePtr_; } + + NodeId GetNodeId() const + { return nodePtr_->GetNodeId(); } + + StorageType& Events() + { return nodePtr->Events(); } + + const StorageType& Events() const + { return nodePtr->Events(); } + + void SetPendingSuccessorCount(size_t count) + { nodePtr_->SetPendingSuccessorCount(count); } + + void DecrementPendingSuccessorCount() + { nodePtr_->DecrementPendingSuccessorCount(); } + +private: + std::shared_ptr nodePtr_; +}; /****************************************/ REACT_IMPL_END /***************************************/ @@ -31,11 +72,8 @@ struct PrivateEventLinkNodeInterface; /// Event /////////////////////////////////////////////////////////////////////////////////////////////////// template -class Event +class Event : protected REACT_IMPL::EventInternals { -private: - using NodeType = REACT_IMPL::EventStreamNode; - public: Event(const Event&) = default; Event& operator=(const Event&) = default; @@ -45,7 +83,7 @@ class Event template Event(F&& func, const Event& dep) : - Event::Event( REACT_IMPL::CtorTag{ }, CreateProcessingNode(std::forward(func), dep) ) + Event::Event( REACT_IMPL::CtorTag{ }, CreateProcessingNode(dep.GetGroup(), std::forward(func), dep) ) { } template @@ -55,7 +93,7 @@ class Event template Event(F&& func, const Event& dep, const Signal& ... signals) : - Event::Event( REACT_IMPL::CtorTag{ }, CreateSyncedProcessingNode(std::forward(func), dep, signals ...) ) + Event::Event( REACT_IMPL::CtorTag{ }, CreateSyncedProcessingNode(dep.GetGroup(), std::forward(func), dep, signals ...) ) { } template @@ -78,44 +116,56 @@ class Event auto Transform(F&& pred) const -> decltype(auto) { return REACT::Transform(*this, std::forward(f)); }*/ -protected: - // Internal node ctor - Event(REACT_IMPL::CtorTag, std::shared_ptr&& nodePtr) : - nodePtr_( std::move(nodePtr) ) - { } + auto GetGroup() const -> const Group& + { return GetNodePtr()->GetGroup(); } - auto NodePtr() -> std::shared_ptr& - { return nodePtr_; } + auto GetGroup() -> Group& + { return GetNodePtr()->GetGroup(); } - auto NodePtr() const -> const std::shared_ptr& - { return nodePtr_; } + friend bool operator==(const Event& a, const Event& b) + { return a.GetNodePtr() == b.GetNodePtr(); } + + friend bool operator!=(const Event& a, const Event& b) + { return !(a == b); } + + friend auto GetInternals(Event& e) -> REACT_IMPL::EventInternals& + { return e; } + + friend auto GetInternals(const Event& e) -> const REACT_IMPL::EventInternals& + { return e; } + +public: // Internal + template + static Event CreateWithNode(TArgs&& ... args) + { + return Event( REACT_IMPL::CtorTag{ }, std::make_shared(std::forward(args) ...) ); + } + +protected: + // Private node ctor + Event(REACT_IMPL::CtorTag, std::shared_ptr>&& nodePtr) : + Event::EventInternals( std::move(nodePtr) ) + { } template - auto CreateProcessingNode(F&& func, const Event& dep) -> decltype(auto) + auto CreateProcessingNode(const Group& group, F&& func, const Event& dep) -> decltype(auto) { - using REACT_IMPL::PrivateNodeInterface; - using EventNodeType = REACT_IMPL::EventProcessingNode::type>; + using REACT_IMPL::EventProcessingNode; + using REACT_IMPL::SameGroupOrLink; - return std::make_shared(PrivateNodeInterface::GraphPtr(dep), std::forward(func), PrivateNodeInterface::NodePtr(dep)); + return std::make_shared::type>>( + group, std::forward(func), SameGroupOrLink(group, dep)); } template - auto CreateSyncedProcessingNode(F&& func, const Event& dep, const Signal& ... syncs) -> decltype(auto) + auto CreateSyncedProcessingNode(const Group& group, F&& func, const Event& dep, const Signal& ... syncs) -> decltype(auto) { - using REACT_IMPL::GetCheckedGraphPtr; - using REACT_IMPL::PrivateNodeInterface; - using EventNodeType = REACT_IMPL::SyncedEventProcessingNode::type, Us ...>; - - return std::make_shared( - GetCheckedGraphPtr(dep, syncs ...), - std::forward(func), - PrivateNodeInterface::NodePtr(dep), PrivateNodeInterface::NodePtr(syncs) ...); - } - -private: - std::shared_ptr nodePtr_; + using REACT_IMPL::SyncedEventProcessingNode; + using REACT_IMPL::SameGroupOrLink; - friend struct REACT_IMPL::PrivateNodeInterface; + return std::make_shared::type, Us ...>>( + group, std::forward(func), SameGroupOrLink(group, dep), SameGroupOrLink(group, syncs) ...); + } }; /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -155,8 +205,8 @@ class EventSource : public Event protected: auto CreateSourceNode(const Group& group) -> decltype(auto) { - using SrcNodeType = REACT_IMPL::EventSourceNode; - return std::make_shared(group); + using REACT_IMPL::EventSourceNode; + return std::make_shared>(group); } private: @@ -167,10 +217,11 @@ class EventSource : public Event using REACT_IMPL::ReactiveGraph; using SrcNodeType = REACT_IMPL::EventSourceNode; - SrcNodeType* castedPtr = static_cast(this->NodePtr().get()); + SrcNodeType* castedPtr = static_cast(this->GetNodePtr().get()); NodeId nodeId = castedPtr->GetNodeId(); - auto& graphPtr = NodePtr()->GraphPtr(); + auto& graphPtr = GetInternals(this->GetGroup()).GetGraphPtr(); + graphPtr->AddInput(nodeId, [castedPtr, &value] { castedPtr->EmitValue(std::forward(value)); }); } }; @@ -188,9 +239,14 @@ class EventSlot : public Event EventSlot(EventSlot&&) = default; EventSlot& operator=(EventSlot&&) = default; - // Construct with value + // Construct with explicit group EventSlot(const Group& group, const Event& input) : - EventSlot::EventSlotBase( REACT_IMPL::CtorTag{ }, CreateSlotNode(group, input) ) + EventSlot::Event( REACT_IMPL::CtorTag{ }, CreateSlotNode(group, input) ) + { } + + // Construct with implicit group + EventSlot(const Event& input) : + EventSlot::Event( REACT_IMPL::CtorTag{ }, CreateSlotNode(input.GetGroup(), input) ) { } void Set(const Event& newInput) @@ -202,9 +258,8 @@ class EventSlot : public Event protected: auto CreateSlotNode(const Group& group, const Event& input) -> decltype(auto) { - using SlotNodeType = REACT_IMPL::EventSlotNode; - - return std::make_shared(group, input); + using REACT_IMPL::EventSlotNode; + return std::make_shared>(group, SameGroupOrLink(input)); } private: @@ -237,27 +292,23 @@ class EventLink : public Event // Construct with explicit group EventLink(const Group& group, const Event& input) : - SignalLink::Signal( REACT_IMPL::CtorTag{ }, CreateLinkNode(group, input) ) + EventLink::Event( REACT_IMPL::CtorTag{ }, CreateLinkNode(group, input) ) { } // Construct with implicit group explicit EventLink(const Event& input) : - SignalLink::Signal( REACT_IMPL::CtorTag{ }, CreateLinkNode(REACT_IMPL::PrivateNodeInterface::GraphPtr(input), input) ) + EventLink::Event( REACT_IMPL::CtorTag{ }, CreateLinkNode(input.GetGroup(), input) ) { } protected: static auto CreateLinkNode(const Group& group, const Event& input) -> decltype(auto) { - using REACT_IMPL::PrivateNodeInterface; - using REACT_IMPL::PrivateGroupInterface; - using EventNodeType = REACT_IMPL::EventLinkNode; + using REACT_IMPL::EventLinkNode; - auto node = std::make_shared(group, PrivateNodeInterface::GraphPtr(input), PrivateNodeInterface::NodePtr(input)); - node->SetWeakSelfPtr(std::weak_ptr{ node }); + auto node = std::make_shared>(group, input); + node->SetWeakSelfPtr(std::weak_ptr>{ node }); return node; } - - friend struct REACT_IMPL::PrivateEventLinkNodeInterface; }; /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -267,9 +318,7 @@ template auto Merge(const Group& group, const Event& dep1, const Event& ... deps) -> decltype(auto) { using REACT_IMPL::EventMergeNode; - using REACT_IMPL::PrivateEventLinkNodeInterface; - using REACT_IMPL::PrivateGroupInterface; - using REACT_IMPL::PrivateNodeInterface; + using REACT_IMPL::SameGroupOrLink; using REACT_IMPL::CtorTag; static_assert(sizeof...(Us) > 0, "Merge requires at least 2 inputs."); @@ -280,33 +329,12 @@ auto Merge(const Group& group, const Event& dep1, const Event& ... deps) typename std::common_type::type, T>::type; - const auto& graphPtr = PrivateGroupInterface::GraphPtr(group); - - return PrivateNodeInterface::CreateNodeHelper, EventMergeNode>( - graphPtr, PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, dep1), PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, deps) ...); + return Event::CreateWithNode>(group, SameGroupOrLink(group, dep1), SameGroupOrLink(group, deps) ...); } template auto Merge(const Event& dep1, const Event& ... deps) -> decltype(auto) -{ - using REACT_IMPL::EventMergeNode; - using REACT_IMPL::PrivateEventLinkNodeInterface; - using REACT_IMPL::PrivateNodeInterface; - using REACT_IMPL::CtorTag; - - static_assert(sizeof...(Us) > 0, "Merge requires at least 2 inputs."); - - // If supplied, use merge type, otherwise default to common type. - using E = typename std::conditional< - std::is_same::value, - typename std::common_type::type, - T>::type; - - const auto& graphPtr = PrivateNodeInterface::GraphPtr(dep1); - - return PrivateNodeInterface::CreateNodeHelper, EventMergeNode>( - graphPtr, PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, dep1), PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, deps) ...); -} + { return Merge(dep1.GetGroup(), dep1, deps ...); } /////////////////////////////////////////////////////////////////////////////////////////////////// /// Filter @@ -322,12 +350,7 @@ auto Filter(const Group& group, F&& pred, const Event& dep) -> Event template auto Filter(F&& pred, const Event& dep) -> Event -{ - auto filterFunc = [capturedPred = std::forward(pred)] (EventRange inRange, EventSink out) - { std::copy_if(inRange.begin(), inRange.end(), out, capturedPred); }; - - return Event(std::move(filterFunc), dep); -} + { return Filter(dep.GetGroup(), std::forward(pred), dep); } template auto Filter(const Group& group, F&& pred, const Event& dep, const Signal& ... signals) -> Event @@ -344,16 +367,7 @@ auto Filter(const Group& group, F&& pred, const Event& dep, const Signal& template auto Filter(F&& pred, const Event& dep, const Signal& ... signals) -> Event -{ - auto filterFunc = [capturedPred = std::forward(pred)] (EventRange inRange, EventSink out, const Us& ... values) - { - for (const auto& v : inRange) - if (capturedPred(v, values ...)) - *out++ = v; - }; - - return Event(std::move(filterFunc), dep, signals ...); -} + { return Filter(dep.GetGroup(), std::forward(pred), dep); } /////////////////////////////////////////////////////////////////////////////////////////////////// /// Transform @@ -369,12 +383,7 @@ auto Transform(const Group& group, F&& op, const Event& dep) -> Event template auto Transform(F&& op, const Event& dep) -> Event -{ - auto transformFunc = [capturedOp = std::forward(op)] (EventRange inRange, EventSink out) - { std::transform(inRange.begin(), inRange.end(), out, capturedOp); }; - - return Event(std::move(transformFunc), dep); -} + { return Transform(dep1.GetGroup(), std::forward(op), dep); } template auto Transform(const Group& group, F&& op, const Event& dep, const Signal& ... signals) -> Event @@ -390,15 +399,7 @@ auto Transform(const Group& group, F&& op, const Event& dep, const Signal template auto Transform(F&& op, const Event& dep, const Signal& ... signals) -> Event -{ - auto transformFunc = [capturedOp = std::forward(pred)] (EventRange inRange, EventSink out, const Vs& ... values) - { - for (const auto& v : inRange) - *out++ = capturedPred(v, values ...); - }; - - return Event(std::move(transformFunc), dep, signals ...); -} + { return Transform(dep.GetGroup(), std::forward(op), dep, signals ...); } /////////////////////////////////////////////////////////////////////////////////////////////////// /// Flatten @@ -418,34 +419,16 @@ template auto Join(const Group& group, const Event& dep1, const Event& ... deps) -> Event> { using REACT_IMPL::EventJoinNode; - using REACT_IMPL::PrivateGroupInterface; - using REACT_IMPL::PrivateEventLinkNodeInterface; - using REACT_IMPL::PrivateNodeInterface; static_assert(sizeof...(Us) > 0, "Join requires at least 2 inputs."); - // If supplied, use merge type, otherwise default to common type. - const auto& graphPtr = PrivateGroupInterface::GraphPtr(group); - - return PrivateNodeInterface::CreateNodeHelper>, EventJoinNode>( - graphPtr, PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, dep1), PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, deps) ...); + return Event>::CreateWithNode>( + group, SameGroupOrLink(group, dep1), SameGroupOrLink(group, deps) ...); } template auto Join(const Event& dep1, const Event& ... deps) -> Event> -{ - using REACT_IMPL::EventJoinNode; - using REACT_IMPL::PrivateEventLinkNodeInterface; - using REACT_IMPL::PrivateNodeInterface; - - static_assert(sizeof...(Us) > 0, "Join requires at least 2 inputs."); - - // If supplied, use merge type, otherwise default to common type. - const auto& graphPtr = PrivateNodeInterface::GraphPtr(dep1); - - return PrivateNodeInterface::CreateNodeHelper>, EventJoinNode>( - graphPtr, PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, dep1), PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, deps) ...); -} + { return Join(dep1.GetGroup(), dep1, deps ...); } /////////////////////////////////////////////////////////////////////////////////////////////////// /// Token @@ -474,23 +457,14 @@ bool Equals(const Event& lhs, const Event& rhs) return lhs.Equals(rhs); } -struct PrivateEventLinkNodeInterface +template +static Event SameGroupOrLink(const Group& targetGroup, const Event& dep) { - template - static auto GetLocalNodePtr(const std::shared_ptr& targetGraph, const Event& dep) -> std::shared_ptr> - { - const std::shared_ptr& sourceGraph = PrivateNodeInterface::GraphPtr(dep); - - if (sourceGraph == targetGraph) - { - return PrivateNodeInterface::NodePtr(dep); - } - else - { - return EventLink::CreateLinkNode(targetGraph, dep); - } - } -}; + if (dep.GetGroup() == targetGroup) + return dep; + else + return EventLink( targetGroup, dep ); +} /****************************************/ REACT_IMPL_END /***************************************/ diff --git a/include/react/Group.h b/include/react/Group.h index 6e9a645d..d68526df 100644 --- a/include/react/Group.h +++ b/include/react/Group.h @@ -21,8 +21,33 @@ /***************************************/ REACT_IMPL_BEGIN /**************************************/ -struct PrivateGroupInterface; -struct CtorTag { }; +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// GroupInternals +/////////////////////////////////////////////////////////////////////////////////////////////////// +class GroupInternals +{ + using GraphType = REACT_IMPL::ReactiveGraph; + +public: + GroupInternals() : + graphPtr_( std::make_shared() ) + { } + + GroupInternals(const GroupInternals&) = default; + GroupInternals& operator=(const GroupInternals&) = default; + + GroupInternals(GroupInternals&&) = default; + GroupInternals& operator=(GroupInternals&&) = default; + + auto GetGraphPtr() -> std::shared_ptr& + { return graphPtr_; } + + auto GetGraphPtr() const -> const std::shared_ptr& + { return graphPtr_; } + +private: + std::shared_ptr graphPtr_; +}; /****************************************/ REACT_IMPL_END /***************************************/ @@ -85,26 +110,22 @@ class TransactionStatus #endif /////////////////////////////////////////////////////////////////////////////////////////////////// -/// GroupBase +/// Group /////////////////////////////////////////////////////////////////////////////////////////////////// -class Group +class Group : protected REACT_IMPL::GroupInternals { - using GraphType = REACT_IMPL::ReactiveGraph; - public: - Group() : - graphPtr_( std::make_shared() ) - { } + Group() = default; Group(const Group&) = default; Group& operator=(const Group&) = default; - Group(Group&& other) = default; - Group& operator=(Group&& other) = default; + Group(Group&&) = default; + Group& operator=(Group&&) = default; template void DoTransaction(F&& func) - { graphPtr_->DoTransaction(std::forward(func)); } + { GetGraphPtr()->DoTransaction(std::forward(func)); } template void EnqueueTransaction(F&& func) @@ -112,18 +133,19 @@ class Group template void EnqueueTransaction(TransactionFlags flags, F&& func) - { graphPtr_->EnqueueTransaction(flags, std::forward(func)); } + { GetGraphPtr()->EnqueueTransaction(flags, std::forward(func)); } + friend bool operator==(const Group& a, const Group& b) + { return a.GetGraphPtr() == b.GetGraphPtr(); } -public: // Internal - auto GraphPtr() -> std::shared_ptr& - { return graphPtr_; } + friend bool operator!=(const Group& a, const Group& b) + { return !(a == b); } - auto GraphPtr() const -> const std::shared_ptr& - { return graphPtr_; } + friend auto GetInternals(Group& g) -> REACT_IMPL::GroupInternals& + { return g; } -private: - std::shared_ptr graphPtr_; + friend auto GetInternals(const Group& g) -> const REACT_IMPL::GroupInternals& + { return g; } }; /******************************************/ REACT_END /******************************************/ diff --git a/include/react/Observer.h b/include/react/Observer.h index b0b64c8e..a2ff497a 100644 --- a/include/react/Observer.h +++ b/include/react/Observer.h @@ -35,22 +35,16 @@ class Observer Observer(Observer&&) = default; Observer& operator=(Observer&&) = default; - // Construct signal observer with implicit group - template - Observer(F&& func, const Signal& ... subjects) : - Observer::Observer(REACT_IMPL::CtorTag{ }, CreateSignalObserverNode(std::forward(func), subjects ...)) - { } - // Construct signal observer with explicit group - template - Observer(const Group& group, F&& func, const Signal& ... subjects) : - Observer::Observer(REACT_IMPL::CtorTag{ }, CreateSignalObserverNode(group, std::forward(func), subjects ...)) + template + Observer(const Group& group, F&& func, const Signal& subject1, const Signal& ... subjects) : + Observer::Observer(REACT_IMPL::CtorTag{ }, CreateSignalObserverNode(group, std::forward(func), subject1, subjects ...)) { } - // Construct event observer with implicit group - template - Observer(F&& func, const Event& subject) : - Observer::Observer(REACT_IMPL::CtorTag{ }, CreateEventObserverNode(std::forward(func), subject)) + // Construct signal observer with implicit group + template + Observer(F&& func, const Signal& subject1, const Signal& ... subjects) : + Observer::Observer(REACT_IMPL::CtorTag{ }, CreateSignalObserverNode(subject1.GetGroup(), std::forward(func), subject1, subjects ...)) { } // Construct event observer with explicit group @@ -59,10 +53,10 @@ class Observer Observer::Observer(REACT_IMPL::CtorTag{ }, CreateEventObserverNode(group, std::forward(func), subject)) { } - // Constructed synced event observer with implicit group - template - Observer(F&& func, const Event& subject, const Signal& ... signals) : - Observer::Observer(REACT_IMPL::CtorTag{ }, CreateSyncedEventObserverNode(std::forward(func), subject, signals ...)) + // Construct event observer with implicit group + template + Observer(F&& func, const Event& subject) : + Observer::Observer(REACT_IMPL::CtorTag{ }, CreateEventObserverNode(subject.GetGroup(), std::forward(func), subject)) { } // Constructed synced event observer with explicit group @@ -71,6 +65,12 @@ class Observer Observer::Observer(REACT_IMPL::CtorTag{ }, CreateSyncedEventObserverNode(group, std::forward(func), subject, signals ...)) { } + // Constructed synced event observer with implicit group + template + Observer(F&& func, const Event& subject, const Signal& ... signals) : + Observer::Observer(REACT_IMPL::CtorTag{ }, CreateSyncedEventObserverNode(subject.GetGroup(), std::forward(func), subject, signals ...)) + { } + public: //Internal // Private node ctor Observer(REACT_IMPL::CtorTag, std::shared_ptr&& nodePtr) : @@ -87,55 +87,29 @@ class Observer template auto CreateSignalObserverNode(const Group& group, F&& func, const Signal& dep1, const Signal& ... deps) -> decltype(auto) { - using REACT_IMPL::PrivateSignalLinkNodeInterface; - using ObsNodeType = REACT_IMPL::SignalObserverNode::type, T1, Ts ...>; - - return std::make_shared( - group, - std::forward(func), - PrivateSignalLinkNodeInterface::GetLocalNodePtr(graphPtr, dep1), PrivateSignalLinkNodeInterface::GetLocalNodePtr(graphPtr, deps) ...); - } - - template - auto CreateSignalObserverNode(F&& func, const Signal& dep1, const Signal& ... deps) -> decltype(auto) - { - return CreateSignalObserverNode(PrivateNodeInterface::GraphPtr(dep1), std::forward(func), dep1, deps ...); + using REACT_IMPL::SignalObserverNode; + return std::make_shared::type, T1, Ts ...>>( + group, std::forward(func), SameGroupOrLink(group, dep1), SameGroupOrLink(group, deps) ...); } template auto CreateEventObserverNode(const Group& group, F&& func, const Event& dep) -> decltype(auto) { - using REACT_IMPL::PrivateEventLinkNodeInterface; - using ObsNodeType = REACT_IMPL::EventObserverNode::type, T>; - - return std::make_shared(group, std::forward(func), PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, dep)); - } - - template - auto CreateEventObserverNode(F&& func, const Event& dep) -> decltype(auto) - { - return CreateEventObserverNode(PrivateNodeInterface::GraphPtr(dep), std::forward(func), dep); + using REACT_IMPL::EventObserverNode; + return std::make_shared::type, T>>( + group, std::forward(func), SameGroupOrLink(group, dep)); } template auto CreateSyncedEventObserverNode(const Group& group, F&& func, const Event& dep, const Signal& ... syncs) -> decltype(auto) { - using REACT_IMPL::PrivateEventLinkNodeInterface; - using REACT_IMPL::PrivateSignalLinkNodeInterface; - using ObsNodeType = REACT_IMPL::SyncedEventObserverNode::type, T, Us ...>; - - return std::make_shared( - graphPtr, std::forward(func), PrivateEventLinkNodeInterface::GetLocalNodePtr(graphPtr, dep), PrivateSignalLinkNodeInterface::GetLocalNodePtr(graphPtr, syncs) ...); - } - - template - auto CreateSyncedEventObserverNode(F&& func, const Event& dep, const Signal& ... syncs) -> decltype(auto) - { - return CreateSyncedEventObserverNode(PrivateNodeInterface::GraphPtr(dep), std::forward(func), dep, syncs ...); + using REACT_IMPL::SyncedEventObserverNode; + return std::make_shared::type, T, Us ...>>( + group, std::forward(func), SameGroupOrLink(group, dep), SameGroupOrLink(group, syncs) ...); } private: - std::shared_ptr nodePtr_;s + std::shared_ptr nodePtr_; }; /******************************************/ REACT_END /******************************************/ diff --git a/include/react/Signal.h b/include/react/Signal.h index bc607a9f..58e5da37 100644 --- a/include/react/Signal.h +++ b/include/react/Signal.h @@ -9,10 +9,6 @@ #pragma once -#if _MSC_VER && !__INTEL_COMPILER - #pragma warning(disable : 4503) -#endif - #include "react/detail/Defs.h" #include "react/API.h" #include "react/Group.h" @@ -26,7 +22,38 @@ /***************************************/ REACT_IMPL_BEGIN /**************************************/ -struct PrivateSignalLinkNodeInterface; +template +class SignalInternals +{ +public: + SignalInternals(const SignalInternals&) = default; + SignalInternals& operator=(const SignalInternals&) = default; + + SignalInternals(SignalInternals&&) = default; + SignalInternals& operator=(SignalInternals&&) = default; + + SignalInternals(std::shared_ptr>&& nodePtr) : + nodePtr_( std::move(nodePtr) ) + { } + + auto GetNodePtr() -> std::shared_ptr>& + { return nodePtr_; } + + auto GetNodePtr() const -> const std::shared_ptr>& + { return nodePtr_; } + + NodeId GetNodeId() const + { return nodePtr_->GetNodeId(); } + + S& Value() + { return nodePtr_->Value(); } + + const S& Value() const + { return nodePtr_->Value(); } + +private: + std::shared_ptr> nodePtr_; +}; /****************************************/ REACT_IMPL_END /***************************************/ @@ -36,11 +63,8 @@ struct PrivateSignalLinkNodeInterface; /// Signal /////////////////////////////////////////////////////////////////////////////////////////////////// template -class Signal +class Signal : protected REACT_IMPL::SignalInternals { -private: - using NodeType = REACT_IMPL::SignalNode; - public: Signal(const Signal&) = default; Signal& operator=(const Signal&) = default; @@ -48,48 +72,53 @@ class Signal Signal(Signal&&) = default; Signal& operator=(Signal&&) = default; - // Construct func signal with explicit group + // Construct with explicit group template explicit Signal(const Group& group, F&& func, const Signal& dep1, const Signal& ... deps) : - Signal::Signal( REACT_IMPL::CtorTag{ }, CreateFuncNode(REACT_IMPL::PrivateGroupInterface::GraphPtr(group), std::forward(func), dep1, deps ...) ) + Signal::SignalInternals( CreateFuncNode(group, std::forward(func), dep1, deps ...) ) { } - // Construct func signal with implicit group + // Construct with implicit group template explicit Signal(F&& func, const Signal& dep1, const Signal& ... deps) : - Signal::Signal( REACT_IMPL::CtorTag{ }, CreateFuncNode(REACT_IMPL::PrivateNodeInterface::GraphPtr(dep1), std::forward(func), dep1, deps ...) ) + Signal::SignalInternals( CreateFuncNode(dep1.GetGroup(), std::forward(func), dep1, deps ...) ) { } - const Group& GetGroup() const - { return nodePtr_->GetGroup(); } + auto GetGroup() const -> const Group& + { return this->GetNodePtr()->GetGroup(); } -public: // Internal - // Private node ctor - Signal(REACT_IMPL::CtorTag, std::shared_ptr&& nodePtr) : - nodePtr_( std::move(nodePtr) ) - { } + auto GetGroup() -> Group& + { return this->GetNodePtr()->GetGroup(); } - auto NodePtr() -> std::shared_ptr& - { return nodePtr_; } + friend bool operator==(const Signal& a, const Signal& b) + { return a.GetNodePtr() == b.GetNodePtr(); } - auto NodePtr() const -> const std::shared_ptr& - { return nodePtr_; } + friend bool operator!=(const Signal& a, const Signal& b) + { return !(a == b); } + + friend auto GetInternals(Signal& s) -> REACT_IMPL::SignalInternals& + { return s; } + + friend auto GetInternals(const Signal& s) -> const REACT_IMPL::SignalInternals& + { return s; } + + template + static Signal CreateWithNode(TArgs&& ... args) + { return Signal( REACT_IMPL::CtorTag{ }, std::make_shared(std::forward(args) ...) ); } protected: + Signal(REACT_IMPL::CtorTag, std::shared_ptr>&& nodePtr) : + Signal::SignalInternals( std::move(nodePtr) ) + { } + template - auto CreateFuncNode(const std::shared_ptr& graphPtr, F&& func, const Signal& dep1, const Signal& ... deps) -> decltype(auto) + auto CreateFuncNode(const Group& group, F&& func, const Signal& dep1, const Signal& ... deps) -> decltype(auto) { - using REACT_IMPL::PrivateSignalLinkNodeInterface; - using FuncNodeType = REACT_IMPL::SignalFuncNode::type, T1, Ts ...>; + using REACT_IMPL::SignalFuncNode; - return std::make_shared( - graphPtr, - std::forward(func), - PrivateSignalLinkNodeInterface::GetLocalNodePtr(graphPtr, dep1), PrivateSignalLinkNodeInterface::GetLocalNodePtr(graphPtr, deps) ...); + return std::make_shared::type, T1, Ts ...>>( + group, std::forward(func), SameGroupOrLink(group, dep1), SameGroupOrLink(group, deps) ...); } - -private: - std::shared_ptr nodePtr_; }; /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -132,18 +161,24 @@ class VarSignal : public Signal void Modify(const F& func) { ModifyValue(func); } + friend bool operator==(const VarSignal& a, VarSignal& b) + { return a.GetNodePtr() == b.GetNodePtr(); } + + friend bool operator!=(const VarSignal& a, VarSignal& b) + { return !(a == b); } + protected: static auto CreateVarNode(const Group& group) -> decltype(auto) { - using VarNodeType = REACT_IMPL::VarSignalNode; - return std::make_shared(graphPtr); + using REACT_IMPL::VarSignalNode; + return std::make_shared>(group); } template static auto CreateVarNode(const Group& group, T&& value) -> decltype(auto) { - using VarNodeType = REACT_IMPL::VarSignalNode; - return std::make_shared(graphPtr, std::forward(value)); + using REACT_IMPL::VarSignalNode; + return std::make_shared>(group, std::forward(value)); } private: @@ -153,10 +188,11 @@ class VarSignal : public Signal using REACT_IMPL::NodeId; using VarNodeType = REACT_IMPL::VarSignalNode; - VarNodeType* castedPtr = static_cast(this->NodePtr().get()); + VarNodeType* castedPtr = static_cast(this->GetNodePtr().get()); NodeId nodeId = castedPtr->GetNodeId(); - auto& graphPtr = NodePtr()->GraphPtr(); + auto& graphPtr = GetInternals(this->GetGroup()).GetGraphPtr(); + graphPtr->AddInput(nodeId, [castedPtr, &newValue] { castedPtr->SetValue(std::forward(newValue)); }); } @@ -166,10 +202,11 @@ class VarSignal : public Signal using REACT_IMPL::NodeId; using VarNodeType = REACT_IMPL::VarSignalNode; - VarNodeType* castedPtr = static_cast(this->NodePtr().get()); + VarNodeType* castedPtr = static_cast(this->GetNodePtr().get()); NodeId nodeId = castedPtr->GetNodeId(); - auto& graphPtr = castedPtr->GraphPtr(); + auto& graphPtr = BaseCast(this->GetGroup()).GetGraphPtr(); + graphPtr->AddInput(nodeId, [castedPtr, &func] { castedPtr->ModifyValue(func); }); } }; @@ -189,17 +226,17 @@ class SignalSlot : public Signal // Construct with group + default explicit SignalSlot(const Group& group) : - SignalSlot::Signal( REACT_IMPL::CtorTag{ }, CreateSlotNode(REACT_IMPL::PrivateGroupInterface::GraphPtr(group)) ) + SignalSlot::Signal( REACT_IMPL::CtorTag{ }, CreateSlotNode(group) ) { } // Construct with group + value SignalSlot(const Group& group, const Signal& input) : - SignalSlot::Signal( REACT_IMPL::CtorTag{ }, CreateSlotNode(REACT_IMPL::PrivateGroupInterface::GraphPtr(group), input) ) + SignalSlot::Signal( REACT_IMPL::CtorTag{ }, CreateSlotNode(group, input) ) { } // Construct with value explicit SignalSlot(const Signal& input) : - SignalSlot::Signal( REACT_IMPL::CtorTag{ }, CreateSlotNode(REACT_IMPL::PrivateNodeInterface::GraphPtr(input), input) ) + SignalSlot::Signal( REACT_IMPL::CtorTag{ }, CreateSlotNode(input.GetGroup(), input) ) { } void Set(const Signal& newInput) @@ -209,26 +246,30 @@ class SignalSlot : public Signal { SetInput(newInput); } protected: - static auto CreateSlotNode(const Group& group, const Signal& input) -> decltype(auto) + static auto CreateSlotNode(const Group& group) -> decltype(auto) { - using REACT_IMPL::PrivateNodeInterface; - using SlotNodeType = REACT_IMPL::SignalSlotNode; + using REACT_IMPL::SignalSlotNode; + return std::make_shared>(group); + } - return std::make_shared(graphPtr, PrivateNodeInterface::NodePtr(input)); + static auto CreateSlotNode(const Group& group, const Signal& input) -> decltype(auto) + { + using REACT_IMPL::SignalSlotNode; + return std::make_shared>(group, input); } private: void SetInput(const Signal& newInput) { - using REACT_IMPL::PrivateNodeInterface; using REACT_IMPL::NodeId; using SlotNodeType = REACT_IMPL::SignalSlotNode; - SlotNodeType* castedPtr = static_cast(this->NodePtr().get()); + SlotNodeType* castedPtr = static_cast(this->GetNodePtr().get()); NodeId nodeId = castedPtr->GetInputNodeId(); - auto& graphPtr = NodePtr()->GraphPtr(); - graphPtr->AddInput(nodeId, [castedPtr, &newInput] { castedPtr->SetInput(PrivateNodeInterface::NodePtr(newInput)); }); + auto& graphPtr = GetInternals(this->GetGroup()).GetGraphPtr(); + + graphPtr->AddInput(nodeId, [castedPtr, &newInput] { castedPtr->SetInput(newInput); }); } }; @@ -258,16 +299,12 @@ class SignalLink : public Signal protected: static auto CreateLinkNode(const Group& group, const Signal& input) -> decltype(auto) { - using REACT_IMPL::PrivateNodeInterface; - using REACT_IMPL::PrivateGroupInterface; - using LinkNodeType = REACT_IMPL::SignalLinkNode; + using REACT_IMPL::SignalLinkNode; - auto node = std::make_shared(graphPtr, PrivateNodeInterface::GraphPtr(input), PrivateNodeInterface::NodePtr(input)); - node->SetWeakSelfPtr(std::weak_ptr{ node }); + auto node = std::make_shared>(group, PrivateNodeInterface::GraphPtr(input), PrivateNodeInterface::NodePtr(input)); + node->SetWeakSelfPtr(std::weak_ptr>{ node }); return node; } - - friend struct REACT_IMPL::PrivateSignalLinkNodeInterface; }; /******************************************/ REACT_END /******************************************/ @@ -280,61 +317,15 @@ bool Equals(const Signal& lhs, const Signal& rhs) return lhs.Equals(rhs); } -struct PrivateSignalLinkNodeInterface +template +static Signal SameGroupOrLink(const Group& targetGroup, const Signal& dep) { - template - static auto GetLocalNodePtr(const std::shared_ptr& targetGraph, const Signal& sig) -> std::shared_ptr> - { - const std::shared_ptr& sourceGraph = PrivateNodeInterface::GraphPtr(sig); - - if (sourceGraph == targetGraph) - { - return PrivateNodeInterface::NodePtr(sig); - } - else - { - return SignalLink::CreateLinkNode(targetGraph, sig); - } - } -}; + if (dep.GetGroup() == targetGroup) + return dep; + else + return SignalLink( group, dep ); +} /****************************************/ REACT_IMPL_END /***************************************/ -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Flatten macros -/////////////////////////////////////////////////////////////////////////////////////////////////// -// Note: Using static_cast rather than -> return type, because when using lambda for inline -// class initialization, decltype did not recognize the parameter r -// Note2: MSVC doesn't like typename in the lambda -#if _MSC_VER && !__INTEL_COMPILER - #define REACT_MSVC_NO_TYPENAME -#else - #define REACT_MSVC_NO_TYPENAME typename -#endif - -#define REACTIVE_REF(obj, name) \ - Flatten( \ - MakeSignal( \ - obj, \ - [] (const REACT_MSVC_NO_TYPENAME \ - REACT_IMPL::Identity::Type::ValueT& r) \ - { \ - using T = decltype(r.name); \ - using S = REACT_MSVC_NO_TYPENAME REACT::DecayInput::Type; \ - return static_cast(r.name); \ - })) - -#define REACTIVE_PTR(obj, name) \ - Flatten( \ - MakeSignal( \ - obj, \ - [] (REACT_MSVC_NO_TYPENAME \ - REACT_IMPL::Identity::Type::ValueT r) \ - { \ - assert(r != nullptr); \ - using T = decltype(r->name); \ - using S = REACT_MSVC_NO_TYPENAME REACT::DecayInput::Type; \ - return static_cast(r->name); \ - })) - #endif // REACT_SIGNAL_H_INCLUDED \ No newline at end of file diff --git a/include/react/detail/Defs.h b/include/react/detail/Defs.h index 24f4cd97..6bdda2e0 100644 --- a/include/react/detail/Defs.h +++ b/include/react/detail/Defs.h @@ -21,22 +21,6 @@ #define REACT_IMPL_END REACT_END } #define REACT_IMPL REACT ::impl -// Assert with message -#define REACT_ASSERT(condition, ...) for (; !(condition); assert(condition)) printf(__VA_ARGS__) -#define REACT_ERROR(...) REACT_ASSERT(false, __VA_ARGS__) - -// Thread local storage -#if _WIN32 || _WIN64 - // MSVC - #define REACT_TLS __declspec(thread) -#elif __GNUC__ - // GCC - #define REACT_TLS __thread -#else - // Standard C++11 - #define REACT_TLS thread_local -#endif - /***************************************/ REACT_IMPL_BEGIN /**************************************/ // Type aliases @@ -44,6 +28,8 @@ using uint = unsigned int; using uchar = unsigned char; using std::size_t; +struct CtorTag { }; + /****************************************/ REACT_IMPL_END /***************************************/ #endif // REACT_DETAIL_DEFS_H_INCLUDED \ No newline at end of file diff --git a/include/react/detail/graph/AlgorithmNodes.h b/include/react/detail/graph/AlgorithmNodes.h index 274581fd..0287a816 100644 --- a/include/react/detail/graph/AlgorithmNodes.h +++ b/include/react/detail/graph/AlgorithmNodes.h @@ -86,8 +86,8 @@ class IterateNode : public SignalNode { public: template - IterateNode(const std::shared_ptr& graphPtr, T&& init, FIn&& func, const std::shared_ptr>& events) : - IterateNode::SignalNode( graphPtr, std::forward(init) ), + IterateNode(const Group& group, T&& init, FIn&& func, const Event& events) : + IterateNode::SignalNode( group, std::forward(init) ), func_( std::forward(func) ), events_( events ) { @@ -125,7 +125,7 @@ class IterateNode : public SignalNode { return 1; } private: - std::shared_ptr> events_; + Event events_; F func_; }; @@ -138,8 +138,8 @@ class IterateByRefNode : public SignalNode { public: template - IterateByRefNode(const std::shared_ptr& graphPtr, T&& init, FIn&& func, const std::shared_ptr>& events) : - IterateByRefNode::SignalNode( graphPtr, std::forward(init) ), + IterateByRefNode(const Group& group, T&& init, FIn&& func, const Event& events) : + IterateByRefNode::SignalNode( group, std::forward(init) ), func_( std::forward(func) ), events_( events ) { @@ -172,7 +172,7 @@ class IterateByRefNode : public SignalNode protected: F func_; - std::shared_ptr> events_; + Event events_; }; /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -183,8 +183,8 @@ class SyncedIterateNode : public SignalNode { public: template - SyncedIterateNode(const std::shared_ptr& graphPtr, T&& init, FIn&& func, const std::shared_ptr>& events, const std::shared_ptr>& ... syncs) : - SyncedIterateNode::SignalNode( graphPtr, std::forward(init) ), + SyncedIterateNode(const Group& group, T&& init, FIn&& func, const Event& events, const Signal& ... syncs) : + SyncedIterateNode::SignalNode( group, std::forward(init) ), func_( std::forward(func) ), events_( events ), syncHolder_( syncs ... ) @@ -236,7 +236,7 @@ class SyncedIterateNode : public SignalNode private: F func_; - std::shared_ptr> events_; + Event events_; std::tuple>...> syncHolder_; }; @@ -249,8 +249,8 @@ class SyncedIterateByRefNode : public SignalNode { public: template - SyncedIterateByRefNode(const std::shared_ptr& graphPtr, T&& init, FIn&& func, const std::shared_ptr>& events, const std::shared_ptr>& ... syncs) : - SyncedIterateByRefNode::SignalNode( graphPtr, std::forward(init) ), + SyncedIterateByRefNode(const Group& group, T&& init, FIn&& func, const Event& events, const Signal& ... syncs) : + SyncedIterateByRefNode::SignalNode( group, std::forward(init) ), func_( std::forward(func) ), events_( events ), syncHolder_( syncs ... ) @@ -294,9 +294,9 @@ class SyncedIterateByRefNode : public SignalNode private: F func_; - std::shared_ptr> events_; + Event events_; - std::tuple>...> syncHolder_; + std::tuple ...> syncHolder_; }; /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -307,8 +307,8 @@ class HoldNode : public SignalNode { public: template - HoldNode(const std::shared_ptr& graphPtr, T&& init, const std::shared_ptr>& events) : - HoldNode::SignalNode( graphPtr, std::forward(init) ), + HoldNode(const Group& group, T&& init, const Event& events) : + HoldNode::SignalNode( group, std::forward(init) ), events_( events ) { this->RegisterMe(); @@ -351,7 +351,7 @@ class HoldNode : public SignalNode { return 1; } private: - const std::shared_ptr> events_; + const Event events_; }; /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -361,8 +361,8 @@ template class SnapshotNode : public SignalNode { public: - SnapshotNode(const std::shared_ptr& graphPtr, const std::shared_ptr>& target, const std::shared_ptr>& trigger) : - SnapshotNode::SignalNode( graphPtr, target->Value() ), + SnapshotNode(const Group& group, const Signal& target, const Event& trigger) : + SnapshotNode::SignalNode( group, target->Value() ), target_( target ), trigger_( trigger ) { @@ -408,8 +408,8 @@ class SnapshotNode : public SignalNode { return 2; } private: - std::shared_ptr> target_; - std::shared_ptr> trigger_; + Signal target_; + Event trigger_; }; /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -419,8 +419,8 @@ template class MonitorNode : public EventStreamNode { public: - MonitorNode(const std::shared_ptr& graphPtr, const std::shared_ptr>& target) : - MonitorNode::EventStreamNode( graphPtr ), + MonitorNode(const Group& group, const Signal& target) : + MonitorNode::EventStreamNode( group ), target_( target ) { this->RegisterMe(); @@ -449,7 +449,7 @@ class MonitorNode : public EventStreamNode { return 1; } private: - std::shared_ptr> target_; + Signal target_; }; /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -459,8 +459,8 @@ template class PulseNode : public EventStreamNode { public: - PulseNode(const std::shared_ptr& graphPtr, const std::shared_ptr>& target, const std::shared_ptr>& trigger) : - PulseNode::EventStreamNode( graphPtr ), + PulseNode(const Group& group, const Signal& target, const Event& trigger) : + PulseNode::EventStreamNode( group ), target_( target ), trigger_( trigger ) { @@ -501,8 +501,8 @@ class PulseNode : public EventStreamNode { return 2; } private: - const std::shared_ptr> target_; - const std::shared_ptr> trigger_; + Signal target_; + Event trigger_; }; /****************************************/ REACT_IMPL_END /***************************************/ diff --git a/include/react/detail/graph/EventNodes.h b/include/react/detail/graph/EventNodes.h index 374038fb..c8d91af0 100644 --- a/include/react/detail/graph/EventNodes.h +++ b/include/react/detail/graph/EventNodes.h @@ -87,8 +87,8 @@ class EventStreamNode : public NodeBase EventStreamNode(const EventStreamNode&) = delete; EventStreamNode& operator=(const EventStreamNode&) = delete; - explicit EventStreamNode(const std::shared_ptr& graphPtr) : - NodeBase( graphPtr ) + explicit EventStreamNode(const Group& group) : + NodeBase( group ) { } StorageType& Events() @@ -122,7 +122,7 @@ class EventStreamNode : public NodeBase // Last successor to arrive clears the buffer. if (pendingSuccessorCount_-- == 1) events_.clear(); - }; + } private: StorageType events_; @@ -137,12 +137,16 @@ template class EventSourceNode : public EventStreamNode { public: - EventSourceNode(const std::shared_ptr& graphPtr) : - EventSourceNode::EventStreamNode( graphPtr ) - { this->RegisterMe(NodeCategory::input); } + EventSourceNode(const Group& group) : + EventSourceNode::EventStreamNode( group ) + { + this->RegisterMe(NodeCategory::input); + } ~EventSourceNode() - { this->UnregisterMe(); } + { + this->UnregisterMe(); + } virtual const char* GetNodeType() const override { return "EventSource"; } @@ -175,8 +179,8 @@ template class EventMergeNode : public EventStreamNode { public: - EventMergeNode(const std::shared_ptr& graphPtr, const std::shared_ptr>& ... deps) : - EventMergeNode::EventStreamNode( graphPtr ), + EventMergeNode(const Group& group, const Event& ... deps) : + EventMergeNode::EventStreamNode( group ), depHolder_( deps ... ) { this->RegisterMe(); @@ -185,7 +189,7 @@ class EventMergeNode : public EventStreamNode ~EventMergeNode() { - apply([this] (const auto& ... deps) { REACT_EXPAND_PACK(this->DetachFromMe(deps->GetNodeId())); }, depHolder_); + apply([this] (const auto& ... deps) { REACT_EXPAND_PACK(this->DetachFromMe(GetInternals(deps).GetNodeId())); }, depHolder_); this->UnregisterMe(); } @@ -212,13 +216,15 @@ class EventMergeNode : public EventStreamNode private: template - void MergeFromDep(const std::shared_ptr>& other) + void MergeFromDep(const Event& dep) { - this->Events().insert(this->Events().end(), other->Events().begin(), other->Events().end()); - other->DecrementPendingSuccessorCount(); + auto& depNodePtr = BaseCast(dep).GetNodePtr(); + + this->Events().insert(this->Events().end(), depNodePtr->Events().begin(), depNodePtr->Events().end()); + depNodePtr->DecrementPendingSuccessorCount(); } - std::tuple> ...> depHolder_; + std::tuple ...> depHolder_; }; /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -228,8 +234,8 @@ template class EventSlotNode : public EventStreamNode { public: - EventSlotNode(const std::shared_ptr& graphPtr, const std::shared_ptr>& dep) : - EventSlotNode::EventStreamNode( graphPtr ), + EventSlotNode(const Group& group, const Event& dep) : + EventSlotNode::EventStreamNode( group ), slotInput_( *this, dep ) { slotInput_.nodeId = GraphPtr()->RegisterNode(&slotInput_, NodeCategory::dyninput); @@ -280,7 +286,7 @@ class EventSlotNode : public EventStreamNode private: struct VirtualInputNode : public IReactiveNode { - VirtualInputNode(EventSlotNode& parentIn, const std::shared_ptr>& depIn) : + VirtualInputNode(EventSlotNode& parentIn, const Event& depIn) : parent( parentIn ), dep( depIn ) { } @@ -312,8 +318,8 @@ class EventSlotNode : public EventStreamNode NodeId nodeId; - std::shared_ptr> dep; - std::shared_ptr> newDep; + Event dep; + Event newDep; }; VirtualInputNode slotInput_; @@ -327,8 +333,8 @@ class EventProcessingNode : public EventStreamNode { public: template - EventProcessingNode(const std::shared_ptr& graphPtr, FIn&& func, const std::shared_ptr>& dep) : - EventProcessingNode::EventStreamNode( graphPtr ), + EventProcessingNode(const Group& group, FIn&& func, const Event& dep) : + EventProcessingNode::EventStreamNode( group ), func_( std::forward(func) ), dep_( dep ) { @@ -368,7 +374,7 @@ class EventProcessingNode : public EventStreamNode private: F func_; - std::shared_ptr> dep_; + Event dep_; }; /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -379,8 +385,8 @@ class SyncedEventProcessingNode : public EventStreamNode { public: template - SyncedEventProcessingNode(const std::shared_ptr& graphPtr, FIn&& func, const std::shared_ptr>& dep, const std::shared_ptr>& ... syncs) : - SyncedEventProcessingNode::EventStreamNode( graphPtr ), + SyncedEventProcessingNode(const Group& group, FIn&& func, const Event& dep, const Signal& ... syncs) : + SyncedEventProcessingNode::EventStreamNode( group ), func_( std::forward(func) ), dep_( dep ), syncHolder_( syncs ... ) @@ -432,9 +438,9 @@ class SyncedEventProcessingNode : public EventStreamNode private: F func_; - std::shared_ptr> dep_; + Event dep_; - std::tuple>...> syncHolder_; + std::tuple ...> syncHolder_; }; /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -444,8 +450,8 @@ template class EventJoinNode : public EventStreamNode> { public: - EventJoinNode(const std::shared_ptr& graphPtr, const std::shared_ptr>& ... deps) : - EventJoinNode::EventStreamNode( graphPtr ), + EventJoinNode(const Group& group, const Event& ... deps) : + EventJoinNode::EventStreamNode( group ), slots_( deps ... ) { this->RegisterMe(); @@ -510,12 +516,12 @@ class EventJoinNode : public EventStreamNode> template struct Slot { - Slot(const std::shared_ptr>& src) : + Slot(const Event& src) : source( src ) { } - std::shared_ptr> source; - std::deque buffer; + Event source; + std::deque buffer; }; template @@ -542,9 +548,9 @@ template class EventLinkNode : public EventStreamNode { public: - EventLinkNode(const std::shared_ptr& graphPtr, const std::shared_ptr& srcGraphPtr, const std::shared_ptr>& dep) : - EventLinkNode::EventStreamNode( graphPtr ), - linkOutput_( srcGraphPtr, dep ) + EventLinkNode(const Group& group, const Event& dep) : + EventLinkNode::EventStreamNode( group ), + linkOutput_( dep ) { this->RegisterMe(NodeCategory::input); } @@ -575,10 +581,10 @@ class EventLinkNode : public EventStreamNode private: struct VirtualOutputNode : public ILinkOutputNode { - VirtualOutputNode(const std::shared_ptr& srcGraphPtrIn, const std::shared_ptr>& depIn) : + VirtualOutputNode(const Event& depIn) : parent( ), - srcGraphPtr( srcGraphPtrIn ), - dep( depIn ) + dep( depIn ), + srcGroup( depIn.GetGroup() ) { nodeId = srcGraphPtr->RegisterNode(this, NodeCategory::linkoutput); srcGraphPtr->OnNodeAttach(nodeId, dep->GetNodeId()); @@ -597,9 +603,7 @@ class EventLinkNode : public EventStreamNode { return 1; } virtual UpdateResult Update(TurnId turnId, size_t successorCount) override - { - return UpdateResult::changed; - } + { return UpdateResult::changed; } virtual void CollectOutput(LinkOutputMap& output) override { @@ -623,11 +627,9 @@ class EventLinkNode : public EventStreamNode std::weak_ptr parent; - NodeId nodeId; - - std::shared_ptr> dep; - - std::shared_ptr srcGraphPtr; + NodeId nodeId; + Event dep; + Group srcGroup; }; VirtualOutputNode linkOutput_; diff --git a/include/react/detail/graph/GraphBase.h b/include/react/detail/graph/GraphBase.h index 3305ca40..a3769ce3 100644 --- a/include/react/detail/graph/GraphBase.h +++ b/include/react/detail/graph/GraphBase.h @@ -58,33 +58,36 @@ class NodeBase : public IReactiveNode NodeId GetNodeId() const { return nodeId_; } - const Group& GetGroup() const + auto GetGroup() const -> const Group& { return group_; } - auto GraphPtr() const -> const std::shared_ptr& - { return GroupInternals::GraphPtr(group_); } - - auto GraphPtr() -> std::shared_ptr& - { return GroupInternals::GraphPtr(group_); } + auto GetGroup() -> Group& + { return group_; } protected: + auto GetGraphPtr() const -> const std::shared_ptr& + { GetInternals(group_).GetGraphPtr(); } + + auto GetGraphPtr() -> std::shared_ptr& + { GetInternals(group_).GetGraphPtr(); } + void RegisterMe(NodeCategory category = NodeCategory::normal) - { nodeId_ = GraphPtr()->RegisterNode(this, category); } + { nodeId_ = GetGraphPtr()->RegisterNode(this, category); } void UnregisterMe() - { GraphPtr()->UnregisterNode(nodeId_); } + { GetGraphPtr()->UnregisterNode(nodeId_); } void AttachToMe(NodeId otherNodeId) - { GraphPtr()->OnNodeAttach(nodeId_, otherNodeId); } + { GetGraphPtr()->OnNodeAttach(nodeId_, otherNodeId); } void DetachFromMe(NodeId otherNodeId) - { GraphPtr()->OnNodeDetach(nodeId_, otherNodeId); } + { GetGraphPtr()->OnNodeDetach(nodeId_, otherNodeId); } void DynamicAttachToMe(NodeId otherNodeId, TurnId turnId) - { GraphPtr()->OnDynamicNodeAttach(nodeId_, otherNodeId, turnId); } + { GetGraphPtr()->OnDynamicNodeAttach(nodeId_, otherNodeId, turnId); } void DynamicDetachFromMe(NodeId otherNodeId, TurnId turnId) - { GraphPtr()->OnDynamicNodeDetach(nodeId_, otherNodeId, turnId); } + { GetGraphPtr()->OnDynamicNodeDetach(nodeId_, otherNodeId, turnId); } private: NodeId nodeId_; diff --git a/include/react/detail/graph/ObserverNodes.h b/include/react/detail/graph/ObserverNodes.h index d383d341..c84e06d0 100644 --- a/include/react/detail/graph/ObserverNodes.h +++ b/include/react/detail/graph/ObserverNodes.h @@ -10,6 +10,7 @@ #pragma once #include "react/detail/Defs.h" +#include "react/API.h" #include #include @@ -35,8 +36,8 @@ class EventStreamNode; class ObserverNode : public NodeBase { public: - ObserverNode(const std::shared_ptr& graphPtr) : - ObserverNode::NodeBase( graphPtr ) + ObserverNode(const Group& group) : + ObserverNode::NodeBase( group ) { } }; @@ -48,18 +49,18 @@ class SignalObserverNode : public ObserverNode { public: template - SignalObserverNode(const std::shared_ptr& graphPtr, FIn&& func, const std::shared_ptr>& ... deps) : - SignalObserverNode::ObserverNode( graphPtr ), + SignalObserverNode(const Group& group, FIn&& func, const Signal& ... deps) : + SignalObserverNode::ObserverNode( group ), func_( std::forward(func) ), depHolder_( deps ... ) { this->RegisterMe(NodeCategory::output); - REACT_EXPAND_PACK(this->AttachToMe(deps->GetNodeId())); + REACT_EXPAND_PACK(this->AttachToMe(GetInternals(deps).GetNodeId())); } ~SignalObserverNode() { - apply([this] (const auto& ... deps) { REACT_EXPAND_PACK(this->DetachFromMe(deps->GetNodeId())); }, depHolder_); + apply([this] (const auto& ... deps) { REACT_EXPAND_PACK(this->DetachFromMe(GetInternals(deps).GetNodeId())); }, depHolder_); this->UnregisterMe(); } @@ -71,14 +72,14 @@ class SignalObserverNode : public ObserverNode virtual UpdateResult Update(TurnId turnId, size_t successorCount) override { - apply([this] (const auto& ... deps) { this->func_(deps->Value() ...); }, depHolder_); + apply([this] (const auto& ... deps) { this->func_(GetInternals(deps).Value() ...); }, depHolder_); return UpdateResult::unchanged; } private: F func_; - std::tuple> ...> depHolder_; + std::tuple ...> depHolder_; }; /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -89,18 +90,18 @@ class EventObserverNode : public ObserverNode { public: template - EventObserverNode(const std::shared_ptr& graphPtr, FIn&& func, const std::shared_ptr>& subject) : - EventObserverNode::ObserverNode( graphPtr ), + EventObserverNode(const Group& group, FIn&& func, const Event& subject) : + EventObserverNode::ObserverNode( group ), func_( std::forward(func) ), subject_( subject ) { this->RegisterMe(NodeCategory::output); - this->AttachToMe(subject->GetNodeId()); + this->AttachToMe(GetInternals(subject).GetNodeId()); } ~EventObserverNode() { - this->DetachFromMe(subject_->GetNodeId()); + this->DetachFromMe(GetInternals(subject_).GetNodeId()); this->UnregisterMe(); } @@ -112,15 +113,15 @@ class EventObserverNode : public ObserverNode virtual UpdateResult Update(TurnId turnId, size_t successorCount) override { - func_(EventRange( subject_->Events() )); - subject_->DecrementPendingSuccessorCount(); + func_(EventRange( GetInternals(subject_).Events() )); + GetInternals(subject_).DecrementPendingSuccessorCount(); return UpdateResult::unchanged; } private: F func_; - std::shared_ptr> subject_; + Event subject_; }; /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -131,21 +132,21 @@ class SyncedEventObserverNode : public ObserverNode { public: template - SyncedEventObserverNode(const std::shared_ptr& graphPtr, FIn&& func, const std::shared_ptr>& subject, const std::shared_ptr>& ... syncs) : - SyncedEventObserverNode::ObserverNode( graphPtr ), + SyncedEventObserverNode(const Group& group, FIn&& func, const Event& subject, const Signal& ... syncs) : + SyncedEventObserverNode::ObserverNode( group ), func_( std::forward(func) ), subject_( subject ), syncHolder_( syncs ... ) { this->RegisterMe(NodeCategory::output); this->AttachToMe(subject->GetNodeId()); - REACT_EXPAND_PACK(this->AttachToMe(syncs->GetNodeId())); + REACT_EXPAND_PACK(this->AttachToMe(GetInternals(syncs).GetNodeId())); } ~SyncedEventObserverNode() { - apply([this] (const auto& ... syncs) { REACT_EXPAND_PACK(this->DetachFromMe(syncs->GetNodeId())); }, syncHolder_); - this->DetachFromMe(subject_->GetNodeId()); + apply([this] (const auto& ... syncs) { REACT_EXPAND_PACK(this->DetachFromMe(GetInternals(syncs).GetNodeId())); }, syncHolder_); + this->DetachFromMe(GetInternals(subject_).GetNodeId()); this->UnregisterMe(); } @@ -158,12 +159,12 @@ class SyncedEventObserverNode : public ObserverNode virtual UpdateResult Update(TurnId turnId, size_t successorCount) override { // Updates might be triggered even if only sync nodes changed. Ignore those. - if (subject_->Events().empty()) + if (GetInternals(this->subject_).Events().empty()) return UpdateResult::unchanged; - apply([this] (const auto& ... syncs) { func_(EventRange( this->subject_->Events() ), syncs->Value() ...); }, syncHolder_); + apply([this] (const auto& ... syncs) { func_(EventRange( GetInternals(this->subject_).Events() ), GetInternals(syncs).Value() ...); }, syncHolder_); - subject_->DecrementPendingSuccessorCount(); + GetInternals(subject_).DecrementPendingSuccessorCount(); return UpdateResult::unchanged; } @@ -171,9 +172,9 @@ class SyncedEventObserverNode : public ObserverNode private: F func_; - std::shared_ptr> subject_; + Event subject_; - std::tuple>...> syncHolder_; + std::tuple ...> syncHolder_; }; /****************************************/ REACT_IMPL_END /***************************************/ diff --git a/include/react/detail/graph/SignalNodes.h b/include/react/detail/graph/SignalNodes.h index 4dbd8574..b25b46d9 100644 --- a/include/react/detail/graph/SignalNodes.h +++ b/include/react/detail/graph/SignalNodes.h @@ -39,14 +39,14 @@ class SignalNode : public NodeBase SignalNode(const SignalNode&) = delete; SignalNode& operator=(const SignalNode&) = delete; - explicit SignalNode(const std::shared_ptr& graphPtr) : - SignalNode::NodeBase( graphPtr ), + explicit SignalNode(const Group& group) : + SignalNode::NodeBase( group ), value_( ) { } template - SignalNode(const std::shared_ptr& graphPtr, T&& value) : - SignalNode::NodeBase( graphPtr ), + SignalNode(const Group& group, T&& value) : + SignalNode::NodeBase( group ), value_( std::forward(value) ) { } @@ -67,19 +67,25 @@ template class VarSignalNode : public SignalNode { public: - explicit VarSignalNode(const std::shared_ptr& graphPtr) : - VarSignalNode::SignalNode( graphPtr ), + explicit VarSignalNode(const Group& group) : + VarSignalNode::SignalNode( group ), newValue_( ) - { this->RegisterMe(NodeCategory::input); } + { + this->RegisterMe(NodeCategory::input); + } template - VarSignalNode(const std::shared_ptr& graphPtr, T&& value) : - VarSignalNode::SignalNode( graphPtr, std::forward(value) ), + VarSignalNode(const Group& group, T&& value) : + VarSignalNode::SignalNode( group, std::forward(value) ), newValue_( value ) - { this->RegisterMe(); } + { + this->RegisterMe(); + } ~VarSignalNode() - { this->UnregisterMe(); } + { + this->UnregisterMe(); + } virtual const char* GetNodeType() const override { return "VarSignal"; } @@ -161,8 +167,8 @@ class SignalFuncNode : public SignalNode { public: template - SignalFuncNode(const std::shared_ptr& graphPtr, FIn&& func, const std::shared_ptr>& ... deps) : - SignalFuncNode::SignalNode( graphPtr, func(deps->Value() ...) ), + SignalFuncNode(const Group& group, FIn&& func, const Signal& ... deps) : + SignalFuncNode::SignalNode( group, func(deps->Value() ...) ), func_( std::forward(func) ), depHolder_( deps ... ) { @@ -172,7 +178,7 @@ class SignalFuncNode : public SignalNode ~SignalFuncNode() { - apply([this] (const auto& ... deps) { REACT_EXPAND_PACK(this->DetachFromMe(deps->GetNodeId())); }, depHolder_); + apply([this] (const auto& ... deps) { REACT_EXPAND_PACK(this->DetachFromMe(GetInternals(deps).GetNodePtr()->GetNodeId())); }, depHolder_); this->UnregisterMe(); } @@ -186,7 +192,7 @@ class SignalFuncNode : public SignalNode { bool changed = false; - S newValue = apply([this] (const auto& ... deps) { return this->func_(deps->Value() ...); }, depHolder_); + S newValue = apply([this] (const auto& ... deps) { return this->func_(GetInternals(deps).Value() ...); }, depHolder_); if (! (this->Value() == newValue)) { @@ -203,7 +209,7 @@ class SignalFuncNode : public SignalNode private: F func_; - std::tuple> ...> depHolder_; + std::tuple ...> depHolder_; }; /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -213,8 +219,8 @@ template class SignalSlotNode : public SignalNode { public: - SignalSlotNode(const std::shared_ptr& graphPtr, const std::shared_ptr>& dep) : - SignalSlotNode::SignalNode( graphPtr, dep->Value() ), + SignalSlotNode(const Group& group, const Signal& dep) : + SignalSlotNode::SignalNode( group, dep->Value() ), slotInput_( *this, dep ) { slotInput_.nodeId = GraphPtr()->RegisterNode(&slotInput_, NodeCategory::dyninput); @@ -226,11 +232,13 @@ class SignalSlotNode : public SignalNode ~SignalSlotNode() { - this->DetachFromMe(slotInput_.dep->GetNodeId()); + const auto& depNodePtr = GetInternals(slotInput_.dep).GetNodePtr(); + + this->DetachFromMe(depNodePtr->GetNodeId()); this->DetachFromMe(slotInput_.nodeId); this->UnregisterMe(); - GraphPtr()->UnregisterNode(slotInput_.nodeId); + GetGraphPtr()->UnregisterNode(slotInput_.nodeId); } virtual const char* GetNodeType() const override @@ -241,9 +249,11 @@ class SignalSlotNode : public SignalNode virtual UpdateResult Update(TurnId turnId, size_t successorCount) override { - if (! (this->Value() == slotInput_.dep->Value())) + const auto& depNodePtr = GetInternals(slotInput_.dep).GetNodePtr(); + + if (! (this->Value() == depNodePtr->Value())) { - this->Value() = slotInput_.dep->Value(); + this->Value() = depNodePtr->Value(); return UpdateResult::changed; } else @@ -252,7 +262,7 @@ class SignalSlotNode : public SignalNode } } - void SetInput(const std::shared_ptr>& newInput) + void SetInput(const Signal& newInput) { slotInput_.newDep = newInput; } NodeId GetInputNodeId() const @@ -261,9 +271,10 @@ class SignalSlotNode : public SignalNode private: struct VirtualInputNode : public IReactiveNode { - VirtualInputNode(SignalSlotNode& parentIn, const std::shared_ptr>& depIn) : + VirtualInputNode(SignalSlotNode& parentIn, const Signal& depIn) : parent( parentIn ), - dep( depIn ) + dep( depIn ), + newDep( depIn ), { } virtual const char* GetNodeType() const override @@ -276,15 +287,17 @@ class SignalSlotNode : public SignalNode { if (dep != newDep) { - parent.DynamicDetachFromMe(dep->GetNodeId(), 0); - parent.DynamicAttachToMe(newDep->GetNodeId(), 0); + const auto& depNodePtr = GetInternals(dep).GetNodePtr(); + const auto& newDepNodePtr = GetInternals(newDep).GetNodePtr(); + + parent.DynamicDetachFromMe(depNodePtr->GetNodeId(), 0); + parent.DynamicAttachToMe(newDepNodePtr->GetNodeId(), 0); dep = std::move(newDep); return UpdateResult::changed; } else { - newDep.reset(); return UpdateResult::unchanged; } } @@ -293,8 +306,8 @@ class SignalSlotNode : public SignalNode NodeId nodeId; - std::shared_ptr> dep; - std::shared_ptr> newDep; + Signal dep; + Signal newDep; }; VirtualInputNode slotInput_; @@ -307,9 +320,9 @@ template class SignalLinkNode : public SignalNode { public: - SignalLinkNode(const std::shared_ptr& graphPtr, const std::shared_ptr& srcGraphPtr, const std::shared_ptr>& dep) : - SignalLinkNode::SignalNode( graphPtr, dep->Value() ), - linkOutput_( srcGraphPtr, dep ) + SignalLinkNode(const Group& group, const Group& srcGroup, const Signal& dep) : + SignalLinkNode::SignalNode( group, dep->Value() ), + linkOutput_( srcGroup, dep ) { this->RegisterMe(NodeCategory::input); } @@ -329,22 +342,18 @@ class SignalLinkNode : public SignalNode { return 1; } virtual UpdateResult Update(TurnId turnId, size_t successorCount) override - { - return UpdateResult::changed; - } + { return UpdateResult::changed; } template void SetValue(T&& newValue) - { - this->Value() = std::forward(newValue); - } + { this->Value() = std::forward(newValue); } private: struct VirtualOutputNode : public ILinkOutputNode { - VirtualOutputNode(const std::shared_ptr& srcGraphPtrIn, const std::shared_ptr>& depIn) : + VirtualOutputNode(const Group& srcGroupIn, const Signal& depIn) : parent( ), - srcGraphPtr( srcGraphPtrIn ), + srcGroup( srcGroupIn ), dep( depIn ) { nodeId = srcGraphPtr->RegisterNode(this, NodeCategory::linkoutput); @@ -364,9 +373,7 @@ class SignalLinkNode : public SignalNode { return 1; } virtual UpdateResult Update(TurnId turnId, size_t successorCount) override - { - return UpdateResult::changed; - } + { return UpdateResult::changed; } virtual void CollectOutput(LinkOutputMap& output) override { @@ -392,9 +399,9 @@ class SignalLinkNode : public SignalNode NodeId nodeId; - std::shared_ptr> dep; + Signal dep; - std::shared_ptr srcGraphPtr; + Group srcGroup; }; VirtualOutputNode linkOutput_; From b70012f98e26479af24eb2ce49b2593c80b5e4eb Mon Sep 17 00:00:00 2001 From: schlangster Date: Wed, 4 Jan 2017 22:17:46 +0100 Subject: [PATCH 47/75] progress --- include/react/Event.h | 14 +- include/react/Signal.h | 27 +--- include/react/detail/graph/AlgorithmNodes.h | 134 ++++++++++---------- include/react/detail/graph/EventNodes.h | 94 ++++++++++---- include/react/detail/graph/GraphBase.h | 4 +- include/react/detail/graph/ObserverNodes.h | 2 +- include/react/detail/graph/SignalNodes.h | 52 ++++---- 7 files changed, 171 insertions(+), 156 deletions(-) diff --git a/include/react/Event.h b/include/react/Event.h index e4d2a987..01c284c6 100644 --- a/include/react/Event.h +++ b/include/react/Event.h @@ -49,10 +49,10 @@ class EventInternals { return nodePtr_->GetNodeId(); } StorageType& Events() - { return nodePtr->Events(); } + { return nodePtr_->Events(); } const StorageType& Events() const - { return nodePtr->Events(); } + { return nodePtr_->Events(); } void SetPendingSuccessorCount(size_t count) { nodePtr_->SetPendingSuccessorCount(count); } @@ -383,7 +383,7 @@ auto Transform(const Group& group, F&& op, const Event& dep) -> Event template auto Transform(F&& op, const Event& dep) -> Event - { return Transform(dep1.GetGroup(), std::forward(op), dep); } + { return Transform(dep.GetGroup(), std::forward(op), dep); } template auto Transform(const Group& group, F&& op, const Event& dep, const Signal& ... signals) -> Event @@ -399,7 +399,7 @@ auto Transform(const Group& group, F&& op, const Event& dep, const Signal template auto Transform(F&& op, const Event& dep, const Signal& ... signals) -> Event - { return Transform(dep.GetGroup(), std::forward(op), dep, signals ...); } + { return Transform(dep.GetGroup(), std::forward(op), dep, signals ...); } /////////////////////////////////////////////////////////////////////////////////////////////////// /// Flatten @@ -451,12 +451,6 @@ auto Tokenize(T&& source) -> decltype(auto) /***************************************/ REACT_IMPL_BEGIN /**************************************/ -template -bool Equals(const Event& lhs, const Event& rhs) -{ - return lhs.Equals(rhs); -} - template static Event SameGroupOrLink(const Group& targetGroup, const Event& dep) { diff --git a/include/react/Signal.h b/include/react/Signal.h index 58e5da37..10ed71f8 100644 --- a/include/react/Signal.h +++ b/include/react/Signal.h @@ -205,7 +205,7 @@ class VarSignal : public Signal VarNodeType* castedPtr = static_cast(this->GetNodePtr().get()); NodeId nodeId = castedPtr->GetNodeId(); - auto& graphPtr = BaseCast(this->GetGroup()).GetGraphPtr(); + auto& graphPtr = GetInternals(this->GetGroup()).GetGraphPtr(); graphPtr->AddInput(nodeId, [castedPtr, &func] { castedPtr->ModifyValue(func); }); } @@ -224,17 +224,12 @@ class SignalSlot : public Signal SignalSlot(SignalSlot&&) = default; SignalSlot& operator=(SignalSlot&&) = default; - // Construct with group + default - explicit SignalSlot(const Group& group) : - SignalSlot::Signal( REACT_IMPL::CtorTag{ }, CreateSlotNode(group) ) - { } - - // Construct with group + value + // Construct with explicit group SignalSlot(const Group& group, const Signal& input) : SignalSlot::Signal( REACT_IMPL::CtorTag{ }, CreateSlotNode(group, input) ) { } - // Construct with value + // Construct with implicit group explicit SignalSlot(const Signal& input) : SignalSlot::Signal( REACT_IMPL::CtorTag{ }, CreateSlotNode(input.GetGroup(), input) ) { } @@ -246,12 +241,6 @@ class SignalSlot : public Signal { SetInput(newInput); } protected: - static auto CreateSlotNode(const Group& group) -> decltype(auto) - { - using REACT_IMPL::SignalSlotNode; - return std::make_shared>(group); - } - static auto CreateSlotNode(const Group& group, const Signal& input) -> decltype(auto) { using REACT_IMPL::SignalSlotNode; @@ -301,7 +290,7 @@ class SignalLink : public Signal { using REACT_IMPL::SignalLinkNode; - auto node = std::make_shared>(group, PrivateNodeInterface::GraphPtr(input), PrivateNodeInterface::NodePtr(input)); + auto node = std::make_shared>(group, input); node->SetWeakSelfPtr(std::weak_ptr>{ node }); return node; } @@ -311,19 +300,13 @@ class SignalLink : public Signal /***************************************/ REACT_IMPL_BEGIN /**************************************/ -template -bool Equals(const Signal& lhs, const Signal& rhs) -{ - return lhs.Equals(rhs); -} - template static Signal SameGroupOrLink(const Group& targetGroup, const Signal& dep) { if (dep.GetGroup() == targetGroup) return dep; else - return SignalLink( group, dep ); + return SignalLink( targetGroup, dep ); } /****************************************/ REACT_IMPL_END /***************************************/ diff --git a/include/react/detail/graph/AlgorithmNodes.h b/include/react/detail/graph/AlgorithmNodes.h index 0287a816..fdb925e1 100644 --- a/include/react/detail/graph/AlgorithmNodes.h +++ b/include/react/detail/graph/AlgorithmNodes.h @@ -86,26 +86,26 @@ class IterateNode : public SignalNode { public: template - IterateNode(const Group& group, T&& init, FIn&& func, const Event& events) : + IterateNode(const Group& group, T&& init, FIn&& func, const Event& evnt) : IterateNode::SignalNode( group, std::forward(init) ), func_( std::forward(func) ), - events_( events ) + evnt_( evnt ) { this->RegisterMe(); - this->AttachToMe(events->GetNodeId()); + this->AttachToMe(GetInternals(evnt).GetNodeId()); } ~IterateNode() { - this->DetachFromMe(events_->GetNodeId()); + this->DetachFromMe(GetInternals(evnt_).GetNodeId()); this->UnregisterMe(); } virtual UpdateResult Update(TurnId turnId, size_t successorCount) override { - S newValue = func_(EventRange( events_->Events() ), this->Value()); + S newValue = func_(EventRange( GetInternals(evnt_).Events() ), this->Value()); - events_->DecrementPendingSuccessorCount(); + GetInternals(evnt_).DecrementPendingSuccessorCount(); if (! (newValue == this->Value())) { @@ -125,9 +125,8 @@ class IterateNode : public SignalNode { return 1; } private: - Event events_; - - F func_; + F func_; + Event evnt_; }; /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -138,26 +137,26 @@ class IterateByRefNode : public SignalNode { public: template - IterateByRefNode(const Group& group, T&& init, FIn&& func, const Event& events) : + IterateByRefNode(const Group& group, T&& init, FIn&& func, const Event& evnt) : IterateByRefNode::SignalNode( group, std::forward(init) ), func_( std::forward(func) ), - events_( events ) + evnt_( evnt ) { this->RegisterMe(); - this->AttachToMe(events->GetNodeId()); + this->AttachToMe(GetInternals(evnt_).GetNodeId()); } ~IterateByRefNode() { - this->DetachFromMe(events_->GetNodeId()); + this->DetachFromMe(GetInternals(evnt).GetNodeId()); this->UnregisterMe(); } virtual UpdateResult Update(TurnId turnId, size_t successorCount) override { - func_(EventRange( events_->Events() ), this->Value()); + func_(EventRange( GetInternals(evnt_).Events() ), this->Value()); - events_->DecrementPendingSuccessorCount(); + GetInternals(evnt_).DecrementPendingSuccessorCount(); // Always assume change return UpdateResult::changed; @@ -170,9 +169,8 @@ class IterateByRefNode : public SignalNode { return 1; } protected: - F func_; - - Event events_; + F func_; + Event evnt_; }; /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -183,38 +181,38 @@ class SyncedIterateNode : public SignalNode { public: template - SyncedIterateNode(const Group& group, T&& init, FIn&& func, const Event& events, const Signal& ... syncs) : + SyncedIterateNode(const Group& group, T&& init, FIn&& func, const Event& evnt, const Signal& ... syncs) : SyncedIterateNode::SignalNode( group, std::forward(init) ), func_( std::forward(func) ), - events_( events ), + evnt_( evnt ), syncHolder_( syncs ... ) { this->RegisterMe(); - this->AttachToMe(events->GetNodeId()); - REACT_EXPAND_PACK(this->AttachToMe(syncs->GetNodeId())); + this->AttachToMe(GetInternals(evnt).GetNodeId()); + REACT_EXPAND_PACK(this->AttachToMe(GetInternals(syncs).GetNodeId())); } ~SyncedIterateNode() { - apply([this] (const auto& ... syncs) { REACT_EXPAND_PACK(this->DetachFromMe(syncs->GetNodeId())); }, syncHolder_); - this->DetachFromMe(events_->GetNodeId()); + apply([this] (const auto& ... syncs) { REACT_EXPAND_PACK(this->DetachFromMe(GetInternals(syncs).GetNodeId())); }, syncHolder_); + this->DetachFromMe(GetInternals(evnt_).GetNodeId()); this->UnregisterMe(); } virtual UpdateResult Update(TurnId turnId, size_t successorCount) override { // Updates might be triggered even if only sync nodes changed. Ignore those. - if (events_->Events().empty()) + if (GetInternals(evnt_).Events().empty()) return UpdateResult::unchanged; S newValue = apply( [this] (const auto& ... syncs) { - return func_(EventRange( events_->Events() ), this->Value(), syncs->Value() ...); + return func_(EventRange( GetInternals(evnt_).Events() ), this->Value(), GetInternals(syncs).Value() ...); }, syncHolder_); - events_->DecrementPendingSuccessorCount(); + GetInternals(evnt_).DecrementPendingSuccessorCount(); if (! (newValue == this->Value())) { @@ -234,11 +232,10 @@ class SyncedIterateNode : public SignalNode { return 1 + sizeof...(TSyncs); } private: - F func_; - - Event events_; + F func_; + Event evnt_; - std::tuple>...> syncHolder_; + std::tuple ...> syncHolder_; }; /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -249,38 +246,38 @@ class SyncedIterateByRefNode : public SignalNode { public: template - SyncedIterateByRefNode(const Group& group, T&& init, FIn&& func, const Event& events, const Signal& ... syncs) : + SyncedIterateByRefNode(const Group& group, T&& init, FIn&& func, const Event& evnt, const Signal& ... syncs) : SyncedIterateByRefNode::SignalNode( group, std::forward(init) ), func_( std::forward(func) ), - events_( events ), + evnt_( evnt ), syncHolder_( syncs ... ) { this->RegisterMe(); - this->AttachToMe(events->GetNodeId()); - REACT_EXPAND_PACK(this->AttachToMe(syncs->GetNodeId())); + this->AttachToMe(GetInternals(evnt).GetNodeId()); + REACT_EXPAND_PACK(this->AttachToMe(GetInternals(syncs).GetNodeId())); } ~SyncedIterateByRefNode() { - apply([this] (const auto& ... syncs) { REACT_EXPAND_PACK(this->DetachFromMe(syncs->GetNodeId())); }, syncHolder_); - this->DetachFromMe(events_->GetNodeId()); + apply([this] (const auto& ... syncs) { REACT_EXPAND_PACK(this->DetachFromMe(GetInternals(syncs).GetNodeId())); }, syncHolder_); + this->DetachFromMe(GetInternals(evnt_).GetNodeId()); this->UnregisterMe(); } virtual UpdateResult Update(TurnId turnId, size_t successorCount) override { // Updates might be triggered even if only sync nodes changed. Ignore those. - if (events_->Events().empty()) + if (GetInternals(evnt_).Events().empty()) return UpdateResult::unchanged; apply( [this] (const auto& ... args) { - func_(EventRange( events_->Events() ), this->Value(), args->Value() ...); + func_(EventRange( GetInternals(evnt_).Events() ), this->Value(), GetInternals(args).Value() ...); }, syncHolder_); - events_->DecrementPendingSuccessorCount(); + GetInternals(evnt_).DecrementPendingSuccessorCount(); return UpdateResult::changed; } @@ -292,9 +289,8 @@ class SyncedIterateByRefNode : public SignalNode { return 1 + sizeof...(TSyncs); } private: - F func_; - - Event events_; + F func_; + Event events_; std::tuple ...> syncHolder_; }; @@ -307,17 +303,17 @@ class HoldNode : public SignalNode { public: template - HoldNode(const Group& group, T&& init, const Event& events) : + HoldNode(const Group& group, T&& init, const Event& evnt) : HoldNode::SignalNode( group, std::forward(init) ), - events_( events ) + evnt_( evnt ) { this->RegisterMe(); - this->AttachToMe(events->GetNodeId()); + this->AttachToMe(GetInternals(evnt).GetNodeId()); } ~HoldNode() { - this->DetachFromMe(events_->GetNodeId()); + this->DetachFromMe(GetInternals(evnt_).GetNodeId()); this->UnregisterMe(); } @@ -328,9 +324,9 @@ class HoldNode : public SignalNode { bool changed = false; - if (! events_->Events().empty()) + if (! GetInternals(evnt_).Events().empty()) { - const S& newValue = events_->Events().back(); + const S& newValue = GetInternals(evnt_).Events().back(); if (! (newValue == this->Value())) { @@ -338,7 +334,7 @@ class HoldNode : public SignalNode this->Value() = newValue; } - events_->DecrementPendingSuccessorCount(); + GetInternals(evnt_).DecrementPendingSuccessorCount(); } if (changed) @@ -351,7 +347,7 @@ class HoldNode : public SignalNode { return 1; } private: - const Event events_; + Event evnt_; }; /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -362,19 +358,19 @@ class SnapshotNode : public SignalNode { public: SnapshotNode(const Group& group, const Signal& target, const Event& trigger) : - SnapshotNode::SignalNode( group, target->Value() ), + SnapshotNode::SignalNode( group, GetInternals(target).Value() ), target_( target ), trigger_( trigger ) { this->RegisterMe(); - this->AttachToMe(target->GetNodeId()); - this->AttachToMe(trigger->GetNodeId()); + this->AttachToMe(GetInternals(target).GetNodeId()); + this->AttachToMe(GetInternals(trigger).GetNodeId()); } ~SnapshotNode() { - this->DetachFromMe(trigger_->GetNodeId()); - this->DetachFromMe(target_->GetNodeId()); + this->DetachFromMe(GetInternals(trigger_).GetNodeId()); + this->DetachFromMe(GetInternals(target_).GetNodeId()); this->UnregisterMe(); } @@ -382,9 +378,9 @@ class SnapshotNode : public SignalNode { bool changed = false; - if (! trigger_->Events().empty()) + if (! GetInternals(trigger_).Events().empty()) { - const S& newValue = target_->Value(); + const S& newValue = GetInternals(target_).Value(); if (! (newValue == this->Value())) { @@ -392,7 +388,7 @@ class SnapshotNode : public SignalNode this->Value() = newValue; } - trigger_->DecrementPendingSuccessorCount(); + GetInternals(trigger_).DecrementPendingSuccessorCount(); } if (changed) @@ -424,18 +420,18 @@ class MonitorNode : public EventStreamNode target_( target ) { this->RegisterMe(); - this->AttachToMe(target->GetNodeId()); + this->AttachToMe(GetInternals(target).GetNodeId()); } ~MonitorNode() { - this->DetachFromMe(target_->GetNodeId()); + this->DetachFromMe(GetInternals(target_).GetNodeId()); this->UnregisterMe(); } virtual UpdateResult Update(TurnId turnId, size_t successorCount) override { - this->Events().push_back(target_->Value()); + this->Events().push_back(GetInternals(target_).Value()); this->SetPendingSuccessorCount(successorCount); @@ -465,23 +461,23 @@ class PulseNode : public EventStreamNode trigger_( trigger ) { this->RegisterMe(); - this->AttachToMe(target->GetNodeId()); - this->AttachToMe(trigger->GetNodeId()); + this->AttachToMe(GetInternals(target).GetNodeId()); + this->AttachToMe(GetInternals(trigger).GetNodeId()); } ~PulseNode() { - this->DetachFromMe(trigger_->GetNodeId()); - this->DetachFromMe(target_->GetNodeId()); + this->DetachFromMe(GetInternals(trigger_).GetNodeId()); + this->DetachFromMe(GetInternals(target_).GetNodeId()); this->UnregisterMe(); } virtual UpdateResult Update(TurnId turnId, size_t successorCount) override { - for (size_t i=0; iEvents().size(); i++) - this->Events().push_back(target_->Value()); + for (size_t i = 0; i < GetInternals(trigger_).Events().size(); i++) + this->Events().push_back(GetInternals(target_).Value()); - trigger_->DecrementPendingSuccessorCount(); + GetInternals(trigger_).DecrementPendingSuccessorCount(); if (! this->Events().empty()) { diff --git a/include/react/detail/graph/EventNodes.h b/include/react/detail/graph/EventNodes.h index c8d91af0..f720fc18 100644 --- a/include/react/detail/graph/EventNodes.h +++ b/include/react/detail/graph/EventNodes.h @@ -184,7 +184,7 @@ class EventMergeNode : public EventStreamNode depHolder_( deps ... ) { this->RegisterMe(); - REACT_EXPAND_PACK(this->AttachToMe(deps->GetNodeId())); + REACT_EXPAND_PACK(this->AttachToMe(GetInternals(deps).GetNodeId())); } ~EventMergeNode() @@ -195,7 +195,7 @@ class EventMergeNode : public EventStreamNode virtual UpdateResult Update(TurnId turnId, size_t successorCount) override { - apply([this] (const auto& ... deps) { REACT_EXPAND_PACK(MergeFromDep(deps)); }, depHolder_); + apply([this] (auto& ... deps) { REACT_EXPAND_PACK(MergeFromDep(deps)); }, depHolder_); if (! this->Events().empty()) { @@ -216,12 +216,13 @@ class EventMergeNode : public EventStreamNode private: template - void MergeFromDep(const Event& dep) + void MergeFromDep(Event& dep) { - auto& depNodePtr = BaseCast(dep).GetNodePtr(); + auto& depInternals = GetInternals(dep); - this->Events().insert(this->Events().end(), depNodePtr->Events().begin(), depNodePtr->Events().end()); - depNodePtr->DecrementPendingSuccessorCount(); + this->Events().insert(this->Events().end(), depInternals.Events().begin(), depInternals.Events().end()); + + depInternals.DecrementPendingSuccessorCount(); } std::tuple ...> depHolder_; @@ -234,20 +235,20 @@ template class EventSlotNode : public EventStreamNode { public: - EventSlotNode(const Group& group, const Event& dep) : + EventSlotNode(const Group& group) : EventSlotNode::EventStreamNode( group ), - slotInput_( *this, dep ) + slotInput_( *this ) { slotInput_.nodeId = GraphPtr()->RegisterNode(&slotInput_, NodeCategory::dyninput); this->RegisterMe(); this->AttachToMe(slotInput_.nodeId); - this->AttachToMe(dep->GetNodeId()); + //this->AttachToMe(GetInternals(dep).GetNodeId()); } ~EventSlotNode() { - this->DetachFromMe(slotInput_.dep->GetNodeId()); + this->DetachFromMe(GetInternals(slotInput_.dep).GetNodeId()); this->DetachFromMe(slotInput_.nodeId); this->UnregisterMe(); @@ -277,8 +278,45 @@ class EventSlotNode : public EventStreamNode } } - void SetInput(const std::shared_ptr>& newInput) - { slotInput_.newDep = newInput; } + void AddInput(const Event>& input) + { + auto& newDeps = slotInput_.newDeps; + + for (auto& e : newDeps) + { + if (e.second != input) + continue; + + // Earlier remove is overridden by later add. + if (e.first == false) + e.first = true; + + // Either element was already added, or remove has been overridden. Nothing more to do. + return; + } + + newDeps.emplace_back(true, input); + } + + void RemoveInput(const Event& input) + { + auto& newDeps = slotInput_.newDeps; + + for (auto& e : newDeps) + { + if (e.second != input) + continue; + + // Earlier add is overridden by later remove. + if (e.first == true) + e.first = false; + + // Either element was already removed, or add has been overridden. Nothing more to do. + return; + } + + newDeps.emplace_back(false, input); + } NodeId GetInputNodeId() const { return slotInput_.nodeId; } @@ -318,8 +356,8 @@ class EventSlotNode : public EventStreamNode NodeId nodeId; - Event dep; - Event newDep; + std::vector> deps; + std::vector>> newDeps; }; VirtualInputNode slotInput_; @@ -339,20 +377,20 @@ class EventProcessingNode : public EventStreamNode dep_( dep ) { this->RegisterMe(); - this->AttachToMe(dep->GetNodeId()); + this->AttachToMe(GetInternals(dep).GetNodeId()); } ~EventProcessingNode() { - this->DetachFromMe(dep_->GetNodeId()); + this->DetachFromMe(GetInternals(dep_).GetNodeId()); this->UnregisterMe(); } virtual UpdateResult Update(TurnId turnId, size_t successorCount) override { - func_(EventRange( dep_->Events() ), std::back_inserter(this->Events())); + func_(EventRange( GetInternals(dep_).Events() ), std::back_inserter(this->Events())); - dep_->DecrementPendingSuccessorCount(); + GetInternals(dep_).DecrementPendingSuccessorCount(); if (! this->Events().empty()) { @@ -455,12 +493,12 @@ class EventJoinNode : public EventStreamNode> slots_( deps ... ) { this->RegisterMe(); - REACT_EXPAND_PACK(this->AttachToMe(deps->GetNodeId())); + REACT_EXPAND_PACK(this->AttachToMe(GetInternals(deps).GetNodeId())); } ~EventJoinNode() { - apply([this] (const auto& ... slots) { REACT_EXPAND_PACK(this->DetachFromMe(slots.source->GetNodeId())); }, slots_); + apply([this] (const auto& ... slots) { REACT_EXPAND_PACK(this->DetachFromMe(GetInternals(slots.source).GetNodeId())); }, slots_); this->UnregisterMe(); } @@ -527,8 +565,8 @@ class EventJoinNode : public EventStreamNode> template static void FetchBuffer(TurnId turnId, Slot& slot) { - slot.buffer.insert(slot.buffer.end(), slot.source->Events().begin(), slot.source->Events().end()); - slot.source->DecrementPendingSuccessorCount(); + slot.buffer.insert(slot.buffer.end(), GetInternals(slot.source).Events().begin(), GetInternals(slot.source).Events().end()); + GetInternals(slot.source).DecrementPendingSuccessorCount(); } template @@ -586,13 +624,15 @@ class EventLinkNode : public EventStreamNode dep( depIn ), srcGroup( depIn.GetGroup() ) { + auto& srcGraphPtr = GetInternals(srcGroup).GetGraphPtr(); nodeId = srcGraphPtr->RegisterNode(this, NodeCategory::linkoutput); - srcGraphPtr->OnNodeAttach(nodeId, dep->GetNodeId()); + srcGraphPtr->OnNodeAttach(nodeId, GetInternals(dep).GetNodeId()); } ~VirtualOutputNode() { - srcGraphPtr->OnNodeDetach(nodeId, dep->GetNodeId()); + auto& srcGraphPtr = GetInternals(srcGroup).GetGraphPtr(); + srcGraphPtr->OnNodeDetach(nodeId, GetInternals(dep).GetNodeId()); srcGraphPtr->UnregisterNode(nodeId); } @@ -609,12 +649,12 @@ class EventLinkNode : public EventStreamNode { if (auto p = parent.lock()) { - auto* rawPtr = p->GraphPtr().get(); + auto* rawPtr = p->GetGraphPtr().get(); output[rawPtr].push_back( - [storedParent = std::move(p), storedEvents = dep->Events()] () mutable + [storedParent = std::move(p), storedEvents = GetInternals(dep).Events()] () mutable { NodeId nodeId = storedParent->GetNodeId(); - auto& graphPtr = storedParent->GraphPtr(); + auto& graphPtr = storedParent->GetGraphPtr(); graphPtr->AddInput(nodeId, [&storedParent, &storedEvents] diff --git a/include/react/detail/graph/GraphBase.h b/include/react/detail/graph/GraphBase.h index a3769ce3..43f58f89 100644 --- a/include/react/detail/graph/GraphBase.h +++ b/include/react/detail/graph/GraphBase.h @@ -66,10 +66,10 @@ class NodeBase : public IReactiveNode protected: auto GetGraphPtr() const -> const std::shared_ptr& - { GetInternals(group_).GetGraphPtr(); } + { return GetInternals(group_).GetGraphPtr(); } auto GetGraphPtr() -> std::shared_ptr& - { GetInternals(group_).GetGraphPtr(); } + { return GetInternals(group_).GetGraphPtr(); } void RegisterMe(NodeCategory category = NodeCategory::normal) { nodeId_ = GetGraphPtr()->RegisterNode(this, category); } diff --git a/include/react/detail/graph/ObserverNodes.h b/include/react/detail/graph/ObserverNodes.h index c84e06d0..695c0792 100644 --- a/include/react/detail/graph/ObserverNodes.h +++ b/include/react/detail/graph/ObserverNodes.h @@ -139,7 +139,7 @@ class SyncedEventObserverNode : public ObserverNode syncHolder_( syncs ... ) { this->RegisterMe(NodeCategory::output); - this->AttachToMe(subject->GetNodeId()); + this->AttachToMe(GetInternals(subject).GetNodeId()); REACT_EXPAND_PACK(this->AttachToMe(GetInternals(syncs).GetNodeId())); } diff --git a/include/react/detail/graph/SignalNodes.h b/include/react/detail/graph/SignalNodes.h index b25b46d9..d137c506 100644 --- a/include/react/detail/graph/SignalNodes.h +++ b/include/react/detail/graph/SignalNodes.h @@ -168,12 +168,12 @@ class SignalFuncNode : public SignalNode public: template SignalFuncNode(const Group& group, FIn&& func, const Signal& ... deps) : - SignalFuncNode::SignalNode( group, func(deps->Value() ...) ), + SignalFuncNode::SignalNode( group, func(GetInternals(deps).Value() ...) ), func_( std::forward(func) ), depHolder_( deps ... ) { this->RegisterMe(); - REACT_EXPAND_PACK(this->AttachToMe(deps->GetNodeId())); + REACT_EXPAND_PACK(this->AttachToMe(GetInternals(deps).GetNodeId())); } ~SignalFuncNode() @@ -220,14 +220,14 @@ class SignalSlotNode : public SignalNode { public: SignalSlotNode(const Group& group, const Signal& dep) : - SignalSlotNode::SignalNode( group, dep->Value() ), + SignalSlotNode::SignalNode( group, GetInternals(dep).Value() ), slotInput_( *this, dep ) { - slotInput_.nodeId = GraphPtr()->RegisterNode(&slotInput_, NodeCategory::dyninput); + slotInput_.nodeId = GetGraphPtr()->RegisterNode(&slotInput_, NodeCategory::dyninput); this->RegisterMe(); this->AttachToMe(slotInput_.nodeId); - this->AttachToMe(dep->GetNodeId()); + this->AttachToMe(GetInternals(dep).GetNodeId()); } ~SignalSlotNode() @@ -263,6 +263,9 @@ class SignalSlotNode : public SignalNode } void SetInput(const Signal& newInput) + { + slotInput_.isChanged = true; + } { slotInput_.newDep = newInput; } NodeId GetInputNodeId() const @@ -273,8 +276,7 @@ class SignalSlotNode : public SignalNode { VirtualInputNode(SignalSlotNode& parentIn, const Signal& depIn) : parent( parentIn ), - dep( depIn ), - newDep( depIn ), + dep( depIn ) { } virtual const char* GetNodeType() const override @@ -306,8 +308,8 @@ class SignalSlotNode : public SignalNode NodeId nodeId; - Signal dep; - Signal newDep; + Signal dep; + bool isChanged = false; }; VirtualInputNode slotInput_; @@ -320,9 +322,9 @@ template class SignalLinkNode : public SignalNode { public: - SignalLinkNode(const Group& group, const Group& srcGroup, const Signal& dep) : - SignalLinkNode::SignalNode( group, dep->Value() ), - linkOutput_( srcGroup, dep ) + SignalLinkNode(const Group& group, const Signal& dep) : + SignalLinkNode::SignalNode( group, GetInternals(dep).Value() ), + linkOutput_( dep ) { this->RegisterMe(NodeCategory::input); } @@ -351,18 +353,20 @@ class SignalLinkNode : public SignalNode private: struct VirtualOutputNode : public ILinkOutputNode { - VirtualOutputNode(const Group& srcGroupIn, const Signal& depIn) : + VirtualOutputNode(const Signal& depIn) : parent( ), - srcGroup( srcGroupIn ), - dep( depIn ) + dep( depIn ), + srcGroup( depIn.GetGroup() ) { + auto& srcGraphPtr = GetInternals(srcGroup).GetGraphPtr(); nodeId = srcGraphPtr->RegisterNode(this, NodeCategory::linkoutput); - srcGraphPtr->OnNodeAttach(nodeId, dep->GetNodeId()); + srcGraphPtr->OnNodeAttach(nodeId, GetInternals(dep).GetNodeId()); } ~VirtualOutputNode() { - srcGraphPtr->OnNodeDetach(nodeId, dep->GetNodeId()); + auto& srcGraphPtr = GetInternals(srcGroup).GetGraphPtr(); + srcGraphPtr->OnNodeDetach(nodeId, GetInternals(dep).GetNodeId()); srcGraphPtr->UnregisterNode(nodeId); } @@ -379,12 +383,12 @@ class SignalLinkNode : public SignalNode { if (auto p = parent.lock()) { - auto* rawPtr = p->GraphPtr().get(); + auto* rawPtr = p->GetGraphPtr().get(); output[rawPtr].push_back( - [storedParent = std::move(p), storedValue = dep->Value()] + [storedParent = std::move(p), storedValue = GetInternals(dep).Value()] { NodeId nodeId = storedParent->GetNodeId(); - auto& graphPtr = storedParent->GraphPtr(); + auto& graphPtr = storedParent->GetGraphPtr(); graphPtr->AddInput(nodeId, [&storedParent, &storedValue] @@ -397,11 +401,9 @@ class SignalLinkNode : public SignalNode std::weak_ptr parent; - NodeId nodeId; - - Signal dep; - - Group srcGroup; + NodeId nodeId; + Signal dep; + Group srcGroup; }; VirtualOutputNode linkOutput_; From 88090f769aab1aa086af9d4b3346be1ffb36cba0 Mon Sep 17 00:00:00 2001 From: schlangster Date: Sat, 7 Jan 2017 10:23:46 +0100 Subject: [PATCH 48/75] progress --- examples/src/BasicObservers.cpp | 22 +- examples/src/BasicSignals.cpp | 15 +- examples/src/Main.cpp | 355 +++++++++++---------- include/react/Event.h | 51 +-- include/react/Signal.h | 2 +- include/react/detail/graph/EventNodes.h | 101 ++---- include/react/detail/graph/PropagationST.h | 30 +- include/react/detail/graph/SignalNodes.h | 67 ++-- 8 files changed, 313 insertions(+), 330 deletions(-) diff --git a/examples/src/BasicObservers.cpp b/examples/src/BasicObservers.cpp index ad263a2e..fede6fd0 100644 --- a/examples/src/BasicObservers.cpp +++ b/examples/src/BasicObservers.cpp @@ -58,17 +58,17 @@ namespace example2 { cout << "Example 2 - Detaching observers manually" << endl; - Observer obs( - [] (EventRange<> in) - { - for (auto _ : in) - cout << "Triggered!" << endl; - }, - trigger); - - trigger.Emit(); // output: Triggered! - - obs.Cancel(); // Remove the observer + { + Observer obs( + [] (EventRange<> in) + { + for (auto _ : in) + cout << "Triggered!" << endl; + }, + trigger); + + trigger.Emit(); // output: Triggered! + } trigger.Emit(); // no output diff --git a/examples/src/BasicSignals.cpp b/examples/src/BasicSignals.cpp index 6bd6771d..a8b6a60a 100644 --- a/examples/src/BasicSignals.cpp +++ b/examples/src/BasicSignals.cpp @@ -26,6 +26,9 @@ namespace example1 string ConcatFunc(string first, string second) { return first + string(" ") + second; } + void PrintFunc(const string& s) + { cout << s << endl; } + // Defines a group. // Each group represents a separate dependency graph. // Reactives from different groups can not be mixed. @@ -40,18 +43,14 @@ namespace example1 void Run() { - cout << "Example 1 - Hello world" << endl; + Observer obs{ PrintFunc, bothWords }; - cout << bothWords.Value() << endl; + cout << "Example 1 - Hello world" << endl; firstWord <<= string("Hello"); - cout << bothWords.Value() << endl; - secondWord <<= string("World"); - cout << bothWords.Value() << endl; - cout << endl; } } @@ -150,8 +149,8 @@ namespace example4 data.Modify([] (vector& data) { data.push_back("World"); }); - for (const auto& s : data.Value()) - cout << s << " "; +// for (const auto& s : data.Value()) +// cout << s << " "; cout << endl; // output: Hello World diff --git a/examples/src/Main.cpp b/examples/src/Main.cpp index cc5fdc31..1ab7a14f 100644 --- a/examples/src/Main.cpp +++ b/examples/src/Main.cpp @@ -17,7 +17,6 @@ using namespace react; - template class GridGraphGenerator { @@ -67,13 +66,13 @@ class GridGraphGenerator if (shouldGrow) { - auto s = SignalType{ group, function1, *l }; + auto s = SignalType{ group, function1, *l }; nextBuf->push_back(std::move(s)); } while (r != curBuf->end()) { - auto s = SignalType{ group, function2, *l, *r }; + auto s = SignalType{ group, function2, *l, *r }; nextBuf->push_back(std::move(s)); ++nodeCount; ++l; ++r; @@ -111,38 +110,38 @@ class GridGraphGenerator template T Multiply(T a, T b) { - return a * b; + return a * b; } template void PrintValue(T v) { - printf("Value: %d\n", v); + printf("Value: %d\n", v); } template void PrintArea(T v) { - printf("Area: %d\n", v); + printf("Area: %d\n", v); } template void PrintVolume(T v) { - printf("Volume: %d\n", v); + printf("Volume: %d\n", v); } template void PrintEvents(EventRange evts) { printf("Processing events...\n"); - for (const auto& e : evts) - printf(" Event: %d\n", e); + for (const auto& e : evts) + printf(" Event: %d\n", e); } template void PrintSyncedEvents(EventRange evts, int a, int b) { - printf("Processing events...\n"); + printf("Processing events...\n"); - for (const auto& e : evts) - printf(" Event: %d, %d, %d\n", e, a, b); + for (const auto& e : evts) + printf(" Event: %d, %d, %d\n", e, a, b); } template bool FilterFunc(T v) @@ -152,166 +151,179 @@ template bool FilterFunc(T v) template T IterFunc1(EventRange evts, T v) { - return v + 1; + return v + 1; } template T IterFunc2(EventRange evts, T v, T a1, T a2) { - return v + 1; + return v + 1; } -int main2() +int main() { - Group group; + Group group; + + { + // Signals + VarSignal x{ group, 0 }; + VarSignal y{ group, 0 }; + VarSignal z{ group, 0 }; + + Signal area{ Multiply, x, y }; + Signal volume{ Multiply, area, z }; + + Observer areaObs{ PrintArea, area }; + Observer volumeObs{ PrintVolume, volume }; - { - // Signals - VarSignal x{ group, 0 }; - VarSignal y{ group, 0 }; - VarSignal z{ group, 0 }; + x.Set(2); // a: 0, v: 0 + y.Set(2); // a: 4, v: 0 + z.Set(2); // a: 4, v: 8 - Signal area{ Multiply, x, y }; - Signal volume{ Multiply, area, z }; + group.DoTransaction([&] + { + x.Set(100); + y <<= 3; + y <<= 4; + }); - Observer areaObs{ PrintArea, area }; - Observer volumeObs{ PrintVolume, volume }; + // a: 400, v: 800 + } - x.Set(2); // a: 0, v: 0 - y.Set(2); // a: 4, v: 0 - z.Set(2); // a: 4, v: 8 + { + // Events + EventSource button1{ group }; + EventSource button2{ group }; - group.DoTransaction([&] - { - x.Set(100); - y <<= 3; - y <<= 4; - }); + Event anyButton = Merge(button1, button2); + Event filtered = Filter(FilterFunc, anyButton); - // a: 400, v: 800 - } + Observer eventObs{ PrintEvents, anyButton }; - { - // Events - EventSource button1{ group }; - EventSource button2{ group }; + button1.Emit(1); + button2.Emit(2); - Event anyButton = Merge(button1, button2); - Event filtered = Filter(FilterFunc, anyButton); + group.DoTransaction([&] + { + for (int i=0; i<10; ++i) + button1.Emit(42); + }); + } - Observer eventObs{ PrintEvents, anyButton }; + { + // Dynamic signals + VarSignal s1{ group, 10 }; + VarSignal s2{ group, 22 }; + + SignalSlot slot{ s1 }; - button1.Emit(1); - button2.Emit(2); + Observer areaObs{ PrintValue, slot }; - group.DoTransaction([&] - { - for (int i=0; i<10; ++i) - button1.Emit(42); - }); - } + s1.Set(42); - { - // Dynamic signals - VarSignal s1{ group, 10 }; - VarSignal s2{ group, 22 }; + slot.Set(s2); - SignalSlot slot{ s1 }; + s2.Set(667); + } - Observer areaObs{ PrintValue, slot }; + { + // Dynamic events + EventSource s1{ group }; + EventSource s2{ group }; - s1.Set(42); + EventSlot slot{ group }; - slot.Set(s2); + Observer eventObs{ PrintEvents, anyButton }; - s2.Set(667); - } + slot.AddInput(s1); + slot.AddInput(s2); + } - // Links - { - Group group1; - Group group2; + // Links + { + Group group1; + Group group2; - VarSignal s1{ group1, 10 }; - VarSignal s2{ group2, 11 }; + VarSignal s1{ group1, 10 }; + VarSignal s2{ group2, 11 }; - Signal v{ Multiply, s1, s2 }; + Signal v{ Multiply, s1, s2 }; - Observer obs{ PrintValue, v }; + Observer obs{ PrintValue, v }; - s1.Set(555); + s1.Set(555); - std::this_thread::sleep_for(std::chrono::seconds(5)); - } + std::this_thread::sleep_for(std::chrono::seconds(5)); + } - { - Group group1; - Group group2; + { + Group group1; + Group group2; - VarSignal s1{ group1, 10 }; - VarSignal s2{ group2, 11 }; + VarSignal s1{ group1, 10 }; + VarSignal s2{ group2, 11 }; - EventSource e1{ group1 }; - EventSource e2{ group2 }; + EventSource e1{ group1 }; + EventSource e2{ group2 }; - auto hold = Hold(group1, 0, e1); + auto hold = Hold(group1, 0, e1); - auto merged = Merge(group2, e1, e2); + auto merged = Merge(group2, e1, e2); - auto joined1 = Join(e1, e2); - auto joined2 = Join(group1, e1, e2); + auto joined1 = Join(e1, e2); + auto joined2 = Join(group1, e1, e2); - Observer eventObs1{ PrintEvents, merged }; - Observer eventObs2{ group2, PrintSyncedEvents, merged, s1, s2 }; + Observer eventObs1{ PrintEvents, merged }; + Observer eventObs2{ group2, PrintSyncedEvents, merged, s1, s2 }; - e1.Emit(222); + e1.Emit(222); - std::this_thread::sleep_for(std::chrono::seconds(5)); - } + std::this_thread::sleep_for(std::chrono::seconds(5)); + } - { - Group group1; - Group group2; + { + Group group1; + Group group2; - VarSignal s1{ group1, 10 }; - VarSignal s2{ group2, 11 }; + VarSignal s1{ group1, 10 }; + VarSignal s2{ group2, 11 }; - EventSource e1{ group1 }; - EventSource e2{ group2 }; + EventSource e1{ group1 }; + EventSource e2{ group2 }; - auto hold1 = Hold(group1, 0, e1); - auto hold2 = Hold(0, e1); + auto hold1 = Hold(group1, 0, e1); + auto hold2 = Hold(0, e1); - auto monitor1 = Monitor(group1, s1); - auto monitor2 = Monitor(s1); + auto monitor1 = Monitor(group1, s1); + auto monitor2 = Monitor(s1); - auto snapshot1 = Snapshot(group1, s1, e1); - auto snapshot2 = Snapshot(s1, e1); + auto snapshot1 = Snapshot(group1, s1, e1); + auto snapshot2 = Snapshot(s1, e1); - auto pulse1 = Pulse(group1, s1, e1); - auto pulse2 = Pulse(s1, e1); + auto pulse1 = Pulse(group1, s1, e1); + auto pulse2 = Pulse(s1, e1); - auto merged = Merge(group2, e1, e2); + auto merged = Merge(group2, e1, e2); - auto joined1 = Join(e1, e2); - auto joined2 = Join(group1, e1, e2); + auto joined1 = Join(e1, e2); + auto joined2 = Join(group1, e1, e2); - auto iter1 = Iterate(group, 0, IterFunc1, e1); - auto iter2 = Iterate(0, IterFunc1, e1); + auto iter1 = Iterate(group, 0, IterFunc1, e1); + auto iter2 = Iterate(0, IterFunc1, e1); - auto iter3 = Iterate(group, 0, IterFunc2, e1, s1, s2); - auto iter4 = Iterate(0, IterFunc2, e1, s1, s2); + auto iter3 = Iterate(group, 0, IterFunc2, e1, s1, s2); + auto iter4 = Iterate(0, IterFunc2, e1, s1, s2); - Observer eventObs{ PrintEvents, merged }; - Observer eventObs2{ group2, PrintSyncedEvents, merged, s1, s2 }; + Observer eventObs{ PrintEvents, merged }; + Observer eventObs2{ group2, PrintSyncedEvents, merged, s1, s2 }; - e1.Emit(222); + e1.Emit(222); - std::this_thread::sleep_for(std::chrono::seconds(5)); + std::this_thread::sleep_for(std::chrono::seconds(5)); - GridGraphGenerator grid; - } + GridGraphGenerator grid; + } - return 0; + return 0; } @@ -324,39 +336,39 @@ int main2() -int main() +int main2() { - Group group; + Group group; - VarSignal in{ group, 1 }; - Signal in2 = in; + VarSignal in{ group, 1 }; + Signal in2 = in; - GridGraphGenerator generator; + GridGraphGenerator generator; - generator.inputSignals.push_back(in2); + generator.inputSignals.push_back(in2); - generator.widths.push_back(100); - generator.widths.push_back(1); + generator.widths.push_back(100); + generator.widths.push_back(1); - int updateCount = 0; + int updateCount = 0; - generator.function1 = [&] (int a) { ++updateCount; return a; }; - generator.function2 = [&] (int a, int b) { ++updateCount; return a + b; }; + generator.function1 = [&] (int a) { ++updateCount; return a; }; + generator.function2 = [&] (int a, int b) { ++updateCount; return a + b; }; - generator.Generate(group); + generator.Generate(group); - updateCount = 0; + updateCount = 0; - auto t0 = tbb::tick_count::now(); - for (int i = 0; i < 10000; i++) - in <<= 10 + i; - auto t1 = tbb::tick_count::now(); + auto t0 = tbb::tick_count::now(); + for (int i = 0; i < 10000; i++) + in <<= 10 + i; + auto t1 = tbb::tick_count::now(); - double d = (t1 - t0).seconds(); - printf("updateCount %d\n", updateCount); - printf("Time %g\n", d); + double d = (t1 - t0).seconds(); + printf("updateCount %d\n", updateCount); + printf("Time %g\n", d); - return 0; + return 0; } @@ -371,47 +383,46 @@ int main() +/* - - -/*int main2() +int main7() { - Group group1; - Group group2; - Group group3; + Group group1; + Group group2; + Group group3; - VarSignal x{ 0, group1 }; - VarSignal y{ 0, group2 }; - VarSignal z{ 0, group3 }; + VarSignal x{ group1, 0 }; + VarSignal y{ group2, 0 }; + VarSignal z{ group3, 0 }; - Signal area{ Multiply, x, y }; - Signal volume{ Multiply, area, z }; + Signal area{ Multiply, x, y }; + Signal volume{ Multiply, area, z }; - Observer obs{ PrintAreaAndVolume, area, volume }; + Observer obs{ PrintAreaAndVolume, area, volume }; - Signal> volumeHistory = Iterate>( vector{ }, PushToVector, Monitor(volume)); + Signal> volumeHistory = Iterate>( vector{ }, PushToVector, Monitor(volume)); - x <<= 2; - y <<= 2; - z <<= 2; + x <<= 2; + y <<= 2; + z <<= 2; - group.DoTransaction([&] - { - x <<= 100; - y <<= 200; - z <<= 300; - }); + group.DoTransaction([&] + { + x <<= 100; + y <<= 200; + z <<= 300; + }); - obs.Cancel(); + obs.Cancel(); - x <<= 42; + x <<= 42; - printf("History:\n"); - for (auto t : volumeHistory.Value()) - printf("%d ", t); - printf("\n"); + printf("History:\n"); + for (auto t : volumeHistory.Value()) + printf("%d ", t); + printf("\n"); - return 0; + return 0; } @@ -421,14 +432,16 @@ int main3() using namespace react; Group group1; - Group group2; + Group group2; auto sig1 = VarSignal( 10, group1 ); auto link1 = SignalLink( sig1, group2 ); - auto link2 = SignalLink( sig1, group2 ); + auto link2 = SignalLink( sig1, group2 ); - sig1.Set(10); + sig1.Set(10); return 0; -}*/ \ No newline at end of file +} + +*/ \ No newline at end of file diff --git a/include/react/Event.h b/include/react/Event.h index 01c284c6..5a7fc42e 100644 --- a/include/react/Event.h +++ b/include/react/Event.h @@ -239,37 +239,37 @@ class EventSlot : public Event EventSlot(EventSlot&&) = default; EventSlot& operator=(EventSlot&&) = default; - // Construct with explicit group - EventSlot(const Group& group, const Event& input) : - EventSlot::Event( REACT_IMPL::CtorTag{ }, CreateSlotNode(group, input) ) + // Construct emtpy slot + EventSlot(const Group& group) : + EventSlot::Event( REACT_IMPL::CtorTag{ }, CreateSlotNode(group) ) { } - // Construct with implicit group - EventSlot(const Event& input) : - EventSlot::Event( REACT_IMPL::CtorTag{ }, CreateSlotNode(input.GetGroup(), input) ) - { } + void Add(const Event& input) + { AddInput(input); } - void Set(const Event& newInput) - { SetInput(newInput); } + void Remove(const Event& input) + { RemoveInput(input); } - void operator<<=(const Event& newInput) - { SetInput(newInput); } + void RemoveAll() + { RemoveAllInputs(); } protected: - auto CreateSlotNode(const Group& group, const Event& input) -> decltype(auto) + auto CreateSlotNode(const Group& group) -> decltype(auto) { using REACT_IMPL::EventSlotNode; - return std::make_shared>(group, SameGroupOrLink(input)); + return std::make_shared>(group); } private: - void SetInput(const Event& newInput) + void AddInput(const Event& input) { + SameGroupOrLink(input) + using REACT_IMPL::NodeId; using REACT_IMPL::ReactiveGraph; using SlotNodeType = REACT_IMPL::EventSlotNode; - SlotNodeType* castedPtr = static_cast(this->NodePtr().get()); + SlotNodeType* castedPtr = static_cast(this->GetNodePtr().get()); NodeId nodeId = castedPtr->GetInputNodeId(); auto& graphPtr = NodePtr()->GraphPtr(); @@ -292,21 +292,24 @@ class EventLink : public Event // Construct with explicit group EventLink(const Group& group, const Event& input) : - EventLink::Event( REACT_IMPL::CtorTag{ }, CreateLinkNode(group, input) ) - { } - - // Construct with implicit group - explicit EventLink(const Event& input) : - EventLink::Event( REACT_IMPL::CtorTag{ }, CreateLinkNode(input.GetGroup(), input) ) + EventLink::Event( REACT_IMPL::CtorTag{ }, GetOrCreateLinkNode(group, input) ) { } protected: - static auto CreateLinkNode(const Group& group, const Event& input) -> decltype(auto) + static auto GetOrCreateLinkNode(const Group& group, const Event& input) -> decltype(auto) { using REACT_IMPL::EventLinkNode; - auto node = std::make_shared>(group, input); - node->SetWeakSelfPtr(std::weak_ptr>{ node }); + const void* inputPtr = GetInternals(input.GetGroup()).GetGraphPtr().get(); + const void* targetPtr = GetInternals(group).GetGraphPtr().get(); + + { + + } + + auto nodePtr = std::make_shared>(group, input); + auto weakPtr = + nodePtr->SetWeakSelfPtr(std::weak_ptr>{ nodePtr }); return node; } }; diff --git a/include/react/Signal.h b/include/react/Signal.h index 10ed71f8..22e237fc 100644 --- a/include/react/Signal.h +++ b/include/react/Signal.h @@ -244,7 +244,7 @@ class SignalSlot : public Signal static auto CreateSlotNode(const Group& group, const Signal& input) -> decltype(auto) { using REACT_IMPL::SignalSlotNode; - return std::make_shared>(group, input); + return std::make_shared>(group, SameGroupOrLink(group, input)); } private: diff --git a/include/react/detail/graph/EventNodes.h b/include/react/detail/graph/EventNodes.h index f720fc18..27d81a41 100644 --- a/include/react/detail/graph/EventNodes.h +++ b/include/react/detail/graph/EventNodes.h @@ -236,23 +236,21 @@ class EventSlotNode : public EventStreamNode { public: EventSlotNode(const Group& group) : - EventSlotNode::EventStreamNode( group ), - slotInput_( *this ) + EventSlotNode::EventStreamNode( group ) { - slotInput_.nodeId = GraphPtr()->RegisterNode(&slotInput_, NodeCategory::dyninput); + inputNodeId_ = GetGraphPtr()->RegisterNode(&slotInput_, NodeCategory::dyninput); this->RegisterMe(); - this->AttachToMe(slotInput_.nodeId); - //this->AttachToMe(GetInternals(dep).GetNodeId()); + this->AttachToMe(inputNodeId_); } ~EventSlotNode() { - this->DetachFromMe(GetInternals(slotInput_.dep).GetNodeId()); - this->DetachFromMe(slotInput_.nodeId); + RemoveAllInputs(); + this->DetachFromMe(inputNodeId_); this->UnregisterMe(); - GraphPtr()->UnregisterNode(slotInput_.nodeId); + GetGraphPtr()->UnregisterNode(inputNodeId_); } virtual const char* GetNodeType() const override @@ -263,7 +261,11 @@ class EventSlotNode : public EventStreamNode virtual UpdateResult Update(TurnId turnId, size_t successorCount) override { - this->Events().insert(this->Events().end(), slotInput_.dep->Events().begin(), slotInput_.dep->Events().end()); + for (const auto& e : deps_) + { + const auto& events = GetInternals(e).Events(); + this->Events().insert(this->Events().end(), events.begin(), events.end()); + } slotInput_.dep->DecrementPendingSuccessorCount(); @@ -278,89 +280,54 @@ class EventSlotNode : public EventStreamNode } } - void AddInput(const Event>& input) + void AddInput(const Event& input) { - auto& newDeps = slotInput_.newDeps; - - for (auto& e : newDeps) + auto it = std::find(inputs_.begin(), inputs_.end(), input); + if (it == inputs_.end()) { - if (e.second != input) - continue; - - // Earlier remove is overridden by later add. - if (e.first == false) - e.first = true; - - // Either element was already added, or remove has been overridden. Nothing more to do. - return; + inputs_.push_back(input); + this->AttachToMe(GetInternals(input).GetNodeId()); } - - newDeps.emplace_back(true, input); } void RemoveInput(const Event& input) { - auto& newDeps = slotInput_.newDeps; - - for (auto& e : newDeps) + auto it = std::find(inputs_.begin(), inputs_.end(), input); + if (it != inputs_.end()) { - if (e.second != input) - continue; - - // Earlier add is overridden by later remove. - if (e.first == true) - e.first = false; - - // Either element was already removed, or add has been overridden. Nothing more to do. - return; + inputs_.erase(it); + this->DetachFromMe(GetInternals(input).GetNodeId()); } + } + + void RemoveAllInputs() + { + for (const auto& e : inputs_) + this->DetachFromMe(GetInternals(e).GetNodeId()); - newDeps.emplace_back(false, input); + inputs_.clear(); } NodeId GetInputNodeId() const - { return slotInput_.nodeId; } + { return inputNodeId_; } private: struct VirtualInputNode : public IReactiveNode { - VirtualInputNode(EventSlotNode& parentIn, const Event& depIn) : - parent( parentIn ), - dep( depIn ) - { } - virtual const char* GetNodeType() const override - { return "EventSlotVirtualInput"; } + { return "EventSlotInput"; } virtual int GetDependencyCount() const override { return 0; } virtual UpdateResult Update(TurnId turnId, size_t successorCount) override - { - if (dep != newDep) - { - parent.DynamicDetachFromMe(dep->GetNodeId(), 0); - parent.DynamicAttachToMe(newDep->GetNodeId(), 0); - - dep = std::move(newDep); - return UpdateResult::changed; - } - else - { - newDep.reset(); - return UpdateResult::unchanged; - } - } - - EventSlotNode& parent; - - NodeId nodeId; - - std::vector> deps; - std::vector>> newDeps; + { return UpdateResult::changed; } }; - VirtualInputNode slotInput_; + std::vector> inputs_; + + NodeId inputNodeId_; + VirtualInputNode slotInput_; }; /////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/include/react/detail/graph/PropagationST.h b/include/react/detail/graph/PropagationST.h index 814fc94c..c9cb6dfc 100644 --- a/include/react/detail/graph/PropagationST.h +++ b/include/react/detail/graph/PropagationST.h @@ -26,6 +26,33 @@ /***************************************/ REACT_IMPL_BEGIN /**************************************/ +template +class PtrCache +{ +public: + void Add(const K& key, const std::shared_ptr& ptr) + { + auto res = map1_.insert(key, ptr); + if (res.first == true) + { + map2_.insert(ptr , res.second); + return true; + } + + } + + void Remove(const std::shared_ptr& ptr) + { + map2_.remove(); + } + +private: + std::mutex lock_; + + std::map> map1_; + std::unordered_map map2_; +}; + class ReactiveGraph; class TransactionQueue @@ -94,9 +121,6 @@ class ReactiveGraph void OnNodeAttach(NodeId node, NodeId parentId); void OnNodeDetach(NodeId node, NodeId parentId); - void OnDynamicNodeAttach(NodeId node, NodeId parentId, TurnId turnId); - void OnDynamicNodeDetach(NodeId node, NodeId parentId, TurnId turnId); - template void AddInput(NodeId nodeId, F&& inputCallback); diff --git a/include/react/detail/graph/SignalNodes.h b/include/react/detail/graph/SignalNodes.h index d137c506..607746ea 100644 --- a/include/react/detail/graph/SignalNodes.h +++ b/include/react/detail/graph/SignalNodes.h @@ -221,24 +221,22 @@ class SignalSlotNode : public SignalNode public: SignalSlotNode(const Group& group, const Signal& dep) : SignalSlotNode::SignalNode( group, GetInternals(dep).Value() ), - slotInput_( *this, dep ) + input_( dep ) { - slotInput_.nodeId = GetGraphPtr()->RegisterNode(&slotInput_, NodeCategory::dyninput); + inputNodeId_ = GetGraphPtr()->RegisterNode(&slotInput_, NodeCategory::dyninput); this->RegisterMe(); - this->AttachToMe(slotInput_.nodeId); + this->AttachToMe(inputNodeId_); this->AttachToMe(GetInternals(dep).GetNodeId()); } ~SignalSlotNode() { - const auto& depNodePtr = GetInternals(slotInput_.dep).GetNodePtr(); - - this->DetachFromMe(depNodePtr->GetNodeId()); - this->DetachFromMe(slotInput_.nodeId); + this->DetachFromMe(GetInternals(input_).GetNodeId()); + this->DetachFromMe(inputNodeId_); this->UnregisterMe(); - GetGraphPtr()->UnregisterNode(slotInput_.nodeId); + GetGraphPtr()->UnregisterNode(inputNodeId_); } virtual const char* GetNodeType() const override @@ -249,11 +247,9 @@ class SignalSlotNode : public SignalNode virtual UpdateResult Update(TurnId turnId, size_t successorCount) override { - const auto& depNodePtr = GetInternals(slotInput_.dep).GetNodePtr(); - - if (! (this->Value() == depNodePtr->Value())) + if (! (this->Value() == GetInternals(input_).Value())) { - this->Value() = depNodePtr->Value(); + this->Value() = GetInternals(input_).Value(); return UpdateResult::changed; } else @@ -264,21 +260,21 @@ class SignalSlotNode : public SignalNode void SetInput(const Signal& newInput) { - slotInput_.isChanged = true; + if (newInput == input_) + return; + + this->DetachFromMe(GetInternals(input_).GetNodeId()); + this->AttachToMe(GetInternals(newInput).GetNodeId()); + + input_ = newInput; } - { slotInput_.newDep = newInput; } NodeId GetInputNodeId() const - { return slotInput_.nodeId; } + { return inputNodeId_; } private: struct VirtualInputNode : public IReactiveNode { - VirtualInputNode(SignalSlotNode& parentIn, const Signal& depIn) : - parent( parentIn ), - dep( depIn ) - { } - virtual const char* GetNodeType() const override { return "SignalSlotInput"; } @@ -286,33 +282,14 @@ class SignalSlotNode : public SignalNode { return 0; } virtual UpdateResult Update(TurnId turnId, size_t successorCount) override - { - if (dep != newDep) - { - const auto& depNodePtr = GetInternals(dep).GetNodePtr(); - const auto& newDepNodePtr = GetInternals(newDep).GetNodePtr(); - - parent.DynamicDetachFromMe(depNodePtr->GetNodeId(), 0); - parent.DynamicAttachToMe(newDepNodePtr->GetNodeId(), 0); - - dep = std::move(newDep); - return UpdateResult::changed; - } - else - { - return UpdateResult::unchanged; - } - } - - SignalSlotNode& parent; - - NodeId nodeId; - - Signal dep; - bool isChanged = false; + { return UpdateResult::changed; } }; - VirtualInputNode slotInput_; + Signal input_; + + NodeId inputNodeId_; + VirtualInputNode slotInput_; + }; /////////////////////////////////////////////////////////////////////////////////////////////////// From d24b490af8f866ad954e1d3413c1b7a00791d58e Mon Sep 17 00:00:00 2001 From: schlangster Date: Sat, 7 Jan 2017 22:17:52 +0100 Subject: [PATCH 49/75] progress --- include/react/Event.h | 59 +++++++++++++++---- include/react/detail/graph/EventNodes.h | 6 +- include/react/detail/graph/GraphBase.h | 6 -- include/react/detail/graph/PropagationST.h | 66 ++++++++++++++-------- 4 files changed, 93 insertions(+), 44 deletions(-) diff --git a/include/react/Event.h b/include/react/Event.h index 5a7fc42e..7020a638 100644 --- a/include/react/Event.h +++ b/include/react/Event.h @@ -263,17 +263,41 @@ class EventSlot : public Event private: void AddInput(const Event& input) { - SameGroupOrLink(input) + using REACT_IMPL::NodeId; + using SlotNodeType = REACT_IMPL::EventSlotNode; + + SlotNodeType* castedPtr = static_cast(this->GetNodePtr().get()); + + NodeId nodeId = castedPtr->GetInputNodeId(); + auto& graphPtr = GetInternals(this->GetGroup()).GetGraphPtr(); + graphPtr->AddInput(nodeId, [castedPtr, &input] { castedPtr->AddInput(input); }); + } + + void RemoveInput(const Event& input) + { using REACT_IMPL::NodeId; - using REACT_IMPL::ReactiveGraph; using SlotNodeType = REACT_IMPL::EventSlotNode; SlotNodeType* castedPtr = static_cast(this->GetNodePtr().get()); NodeId nodeId = castedPtr->GetInputNodeId(); - auto& graphPtr = NodePtr()->GraphPtr(); - graphPtr->AddInput(nodeId, [castedPtr, &newInput] { castedPtr->SetInput(PrivateNodeInterface::NodePtr(newInput)); }); + auto& graphPtr = GetInternals(this->GetGroup()).GetGraphPtr(); + + graphPtr->AddInput(nodeId, [castedPtr, &input] { castedPtr->RemoveInput(input); }); + } + + void RemoveAllInputs() + { + using REACT_IMPL::NodeId; + using SlotNodeType = REACT_IMPL::EventSlotNode; + + SlotNodeType* castedPtr = static_cast(this->GetNodePtr().get()); + + NodeId nodeId = castedPtr->GetInputNodeId(); + auto& graphPtr = GetInternals(this->GetGroup()).GetGraphPtr(); + + graphPtr->AddInput(nodeId, [castedPtr] { castedPtr->RemoveAllInputs(); }); } }; @@ -295,22 +319,33 @@ class EventLink : public Event EventLink::Event( REACT_IMPL::CtorTag{ }, GetOrCreateLinkNode(group, input) ) { } + ~EventLink() + { + auto nodePtr = GetNodePtr(); + } + protected: static auto GetOrCreateLinkNode(const Group& group, const Event& input) -> decltype(auto) { using REACT_IMPL::EventLinkNode; - const void* inputPtr = GetInternals(input.GetGroup()).GetGraphPtr().get(); - const void* targetPtr = GetInternals(group).GetGraphPtr().get(); + auto targetGraphPtr = GetInternals(group).GetGraphPtr(); + + void* k1 = GetInternals(input.GetGroup()).GetGraphPtr().get(); + void* k2 = GetInternals(input).GetNodePtr().get(); - { + auto& linkCache = targetGraphPtr->GetLinkCache(); - } + auto nodePtr = linkCache.LookupOrCreate>( + { k1, k2 }, + [&] + { + auto nodePtr = std::make_shared>(group, input); + nodePtr->SetWeakSelfPtr(std::weak_ptr>{ nodePtr }); + return nodePtr; + }); - auto nodePtr = std::make_shared>(group, input); - auto weakPtr = - nodePtr->SetWeakSelfPtr(std::weak_ptr>{ nodePtr }); - return node; + return nodePtr; } }; diff --git a/include/react/detail/graph/EventNodes.h b/include/react/detail/graph/EventNodes.h index 27d81a41..2ccccca3 100644 --- a/include/react/detail/graph/EventNodes.h +++ b/include/react/detail/graph/EventNodes.h @@ -261,13 +261,13 @@ class EventSlotNode : public EventStreamNode virtual UpdateResult Update(TurnId turnId, size_t successorCount) override { - for (const auto& e : deps_) + for (auto& e : inputs_) { const auto& events = GetInternals(e).Events(); this->Events().insert(this->Events().end(), events.begin(), events.end()); - } - slotInput_.dep->DecrementPendingSuccessorCount(); + GetInternals(e).DecrementPendingSuccessorCount(); + } if (! this->Events().empty()) { diff --git a/include/react/detail/graph/GraphBase.h b/include/react/detail/graph/GraphBase.h index 43f58f89..65f8d1f7 100644 --- a/include/react/detail/graph/GraphBase.h +++ b/include/react/detail/graph/GraphBase.h @@ -83,12 +83,6 @@ class NodeBase : public IReactiveNode void DetachFromMe(NodeId otherNodeId) { GetGraphPtr()->OnNodeDetach(nodeId_, otherNodeId); } - void DynamicAttachToMe(NodeId otherNodeId, TurnId turnId) - { GetGraphPtr()->OnDynamicNodeAttach(nodeId_, otherNodeId, turnId); } - - void DynamicDetachFromMe(NodeId otherNodeId, TurnId turnId) - { GetGraphPtr()->OnDynamicNodeDetach(nodeId_, otherNodeId, turnId); } - private: NodeId nodeId_; diff --git a/include/react/detail/graph/PropagationST.h b/include/react/detail/graph/PropagationST.h index c9cb6dfc..fd2640fd 100644 --- a/include/react/detail/graph/PropagationST.h +++ b/include/react/detail/graph/PropagationST.h @@ -16,6 +16,8 @@ #include #include #include +#include +#include #include #include @@ -30,27 +32,49 @@ template class PtrCache { public: - void Add(const K& key, const std::shared_ptr& ptr) + template + std::shared_ptr LookupOrCreate(const K& key, F&& createFunc) { - auto res = map1_.insert(key, ptr); - if (res.first == true) + std::lock_guard scopedLock(mutex_); + + auto it = map1_.find(key); + + if (it != map1_.end()) { - map2_.insert(ptr , res.second); - return true; + if (auto ptr = it->second.lock()) + { + return std::static_pointer_cast(ptr); + } } - + + std::shared_ptr v = createFunc(); + auto res = map1_.insert({ key, std::weak_ptr{ v } }); + map2_[v.get()] = res.first; + return v; } - void Remove(const std::shared_ptr& ptr) + template + void Erase(const std::shared_ptr& ptr) { - map2_.remove(); + std::lock_guard scopedLock(mutex_); + + auto it = map2_.find((void*)ptr.get()); + + if (it != map2_.end()) + { + map1_.erase(it->second); + map2_.erase(it); + } } private: - std::mutex lock_; + std::mutex mutex_; + + using Map1Type = std::map>; + using Map2Type = std::unordered_map; - std::map> map1_; - std::unordered_map map2_; + Map1Type map1_; + Map2Type map2_; }; class ReactiveGraph; @@ -115,6 +139,8 @@ class TransactionQueue class ReactiveGraph { public: + using LinkCacheType = PtrCache>; + NodeId RegisterNode(IReactiveNode* nodePtr, NodeCategory category); void UnregisterNode(NodeId nodeId); @@ -129,6 +155,9 @@ class ReactiveGraph template void EnqueueTransaction(TransactionFlags flags, F&& transactionCallback); + + LinkCacheType& GetLinkCache() + { return linkCache_; } private: struct NodeData @@ -189,7 +218,9 @@ class ReactiveGraph TopoQueue scheduledNodes_; IndexMap nodeData_; std::vector changedInputs_; - LinkOutputMap scheduledLinkOutputs_; + LinkOutputMap scheduledLinkOutputs_; + + LinkCacheType linkCache_; bool isTransactionActive_ = false; }; @@ -202,7 +233,6 @@ NodeId ReactiveGraph::RegisterNode(IReactiveNode* nodePtr, NodeCategory category void ReactiveGraph::UnregisterNode(NodeId nodeId) { nodeData_.Remove(nodeId); - } void ReactiveGraph::OnNodeAttach(NodeId nodeId, NodeId parentId) @@ -224,16 +254,6 @@ void ReactiveGraph::OnNodeDetach(NodeId nodeId, NodeId parentId) successors.erase(std::find(successors.begin(), successors.end(), nodeId)); } -void ReactiveGraph::OnDynamicNodeAttach(NodeId nodeId, NodeId parentId, TurnId turnId) -{ - OnNodeAttach(nodeId, parentId); -} - -void ReactiveGraph::OnDynamicNodeDetach(NodeId nodeId, NodeId parentId, TurnId turnId) -{ - OnNodeDetach(nodeId, parentId); -} - template void ReactiveGraph::AddInput(NodeId nodeId, F&& inputCallback) { From 20f0149bdee34cc3fa68a1908b4b950842f45e40 Mon Sep 17 00:00:00 2001 From: schlangster Date: Sun, 8 Jan 2017 01:07:01 +0100 Subject: [PATCH 50/75] done with link cache --- examples/src/Main.cpp | 48 ++++++++++++++++++++-- include/react/Event.h | 18 +++----- include/react/Signal.h | 33 +++++++++------ include/react/detail/graph/EventNodes.h | 3 ++ include/react/detail/graph/PropagationST.h | 4 +- include/react/detail/graph/SignalNodes.h | 3 ++ 6 files changed, 79 insertions(+), 30 deletions(-) diff --git a/examples/src/Main.cpp b/examples/src/Main.cpp index 1ab7a14f..5720dcf1 100644 --- a/examples/src/Main.cpp +++ b/examples/src/Main.cpp @@ -159,7 +159,7 @@ template T IterFunc2(EventRange evts, T v, T a1, T a2) return v + 1; } -int main() +int main1() { Group group; @@ -232,10 +232,13 @@ int main() EventSlot slot{ group }; - Observer eventObs{ PrintEvents, anyButton }; + Observer eventObs{ PrintEvents, slot }; + + slot.Add(s1); + slot.Add(s2); - slot.AddInput(s1); - slot.AddInput(s2); + slot.Remove(s1); + slot.RemoveAll(); } // Links @@ -327,7 +330,44 @@ int main() } +int main() +{ + Group group; + + Group extGroup; + + // Dynamic events + EventSource s1{ group }; + EventSource s2{ group }; + EventSource s3{ extGroup }; + //EventSource s4{ extGroup }; + + EventSlot slot{ group }; + + Observer eventObs{ PrintEvents, slot }; + //Observer extObs{ PrintEvents, link1 }; + + //slot.Add(s1); + //slot.Add(s2); + group.DoTransaction([&] + { + s1.Emit(1); + s2.Emit(2); + + + slot.Add(s3); + slot.Add(s3); + slot.Add(s3); + slot.Add(s3); + }); + + s3.Emit(3); + + std::this_thread::sleep_for(std::chrono::seconds(5)); + + return 0; +} diff --git a/include/react/Event.h b/include/react/Event.h index 7020a638..5d97dfff 100644 --- a/include/react/Event.h +++ b/include/react/Event.h @@ -271,7 +271,7 @@ class EventSlot : public Event NodeId nodeId = castedPtr->GetInputNodeId(); auto& graphPtr = GetInternals(this->GetGroup()).GetGraphPtr(); - graphPtr->AddInput(nodeId, [castedPtr, &input] { castedPtr->AddInput(input); }); + graphPtr->AddInput(nodeId, [this, castedPtr, &input] { castedPtr->AddInput(SameGroupOrLink(GetGroup(), input)); }); } void RemoveInput(const Event& input) @@ -284,7 +284,7 @@ class EventSlot : public Event NodeId nodeId = castedPtr->GetInputNodeId(); auto& graphPtr = GetInternals(this->GetGroup()).GetGraphPtr(); - graphPtr->AddInput(nodeId, [castedPtr, &input] { castedPtr->RemoveInput(input); }); + graphPtr->AddInput(nodeId, [this, castedPtr, &input] { castedPtr->RemoveInput(SameGroupOrLink(GetGroup(), input)); }); } void RemoveAllInputs() @@ -314,28 +314,22 @@ class EventLink : public Event EventLink(EventLink&&) = default; EventLink& operator=(EventLink&&) = default; - // Construct with explicit group + // Construct with group EventLink(const Group& group, const Event& input) : EventLink::Event( REACT_IMPL::CtorTag{ }, GetOrCreateLinkNode(group, input) ) { } - ~EventLink() - { - auto nodePtr = GetNodePtr(); - } - protected: static auto GetOrCreateLinkNode(const Group& group, const Event& input) -> decltype(auto) { using REACT_IMPL::EventLinkNode; - auto targetGraphPtr = GetInternals(group).GetGraphPtr(); + auto& targetGraphPtr = GetInternals(group).GetGraphPtr(); + auto& linkCache = targetGraphPtr->GetLinkCache(); void* k1 = GetInternals(input.GetGroup()).GetGraphPtr().get(); void* k2 = GetInternals(input).GetNodePtr().get(); - auto& linkCache = targetGraphPtr->GetLinkCache(); - auto nodePtr = linkCache.LookupOrCreate>( { k1, k2 }, [&] @@ -495,7 +489,7 @@ static Event SameGroupOrLink(const Group& targetGroup, const Event& dep) if (dep.GetGroup() == targetGroup) return dep; else - return EventLink( targetGroup, dep ); + return EventLink{ targetGroup, dep }; } /****************************************/ REACT_IMPL_END /***************************************/ diff --git a/include/react/Signal.h b/include/react/Signal.h index 22e237fc..a429f34b 100644 --- a/include/react/Signal.h +++ b/include/react/Signal.h @@ -258,7 +258,7 @@ class SignalSlot : public Signal NodeId nodeId = castedPtr->GetInputNodeId(); auto& graphPtr = GetInternals(this->GetGroup()).GetGraphPtr(); - graphPtr->AddInput(nodeId, [castedPtr, &newInput] { castedPtr->SetInput(newInput); }); + graphPtr->AddInput(nodeId, [this, castedPtr, &newInput] { castedPtr->SetInput(SameGroupOrLink(GetGroup(), newInput)); }); } }; @@ -275,24 +275,33 @@ class SignalLink : public Signal SignalLink(SignalLink&&) = default; SignalLink& operator=(SignalLink&&) = default; - // Construct with explicit group + // Construct with group SignalLink(const Group& group, const Signal& input) : - SignalLink::Signal( REACT_IMPL::CtorTag{ }, CreateLinkNode(group, input) ) - { } - - // Construct with implicit group - explicit SignalLink(const Signal& input) : - SignalLink::Signal( REACT_IMPL::CtorTag{ }, CreateLinkNode(input.GetGroup(), input) ) + SignalLink::Signal( REACT_IMPL::CtorTag{ }, GetOrCreateLinkNode(group, input) ) { } protected: - static auto CreateLinkNode(const Group& group, const Signal& input) -> decltype(auto) + static auto GetOrCreateLinkNode(const Group& group, const Signal& input) -> decltype(auto) { using REACT_IMPL::SignalLinkNode; - auto node = std::make_shared>(group, input); - node->SetWeakSelfPtr(std::weak_ptr>{ node }); - return node; + auto targetGraphPtr = GetInternals(group).GetGraphPtr(); + + void* k1 = GetInternals(input.GetGroup()).GetGraphPtr().get(); + void* k2 = GetInternals(input).GetNodePtr().get(); + + auto& linkCache = targetGraphPtr->GetLinkCache(); + + auto nodePtr = linkCache.LookupOrCreate>( + { k1, k2 }, + [&] + { + auto nodePtr = std::make_shared>(group, input); + nodePtr->SetWeakSelfPtr(std::weak_ptr>{ nodePtr }); + return nodePtr; + }); + + return nodePtr; } }; diff --git a/include/react/detail/graph/EventNodes.h b/include/react/detail/graph/EventNodes.h index 2ccccca3..e216b4b5 100644 --- a/include/react/detail/graph/EventNodes.h +++ b/include/react/detail/graph/EventNodes.h @@ -562,6 +562,9 @@ class EventLinkNode : public EventStreamNode ~EventLinkNode() { + auto& linkCache = GetGraphPtr()->GetLinkCache(); + linkCache.Erase(this); + this->UnregisterMe(); } diff --git a/include/react/detail/graph/PropagationST.h b/include/react/detail/graph/PropagationST.h index fd2640fd..d1cead73 100644 --- a/include/react/detail/graph/PropagationST.h +++ b/include/react/detail/graph/PropagationST.h @@ -54,11 +54,11 @@ class PtrCache } template - void Erase(const std::shared_ptr& ptr) + void Erase(V* ptr) { std::lock_guard scopedLock(mutex_); - auto it = map2_.find((void*)ptr.get()); + auto it = map2_.find((void*)ptr); if (it != map2_.end()) { diff --git a/include/react/detail/graph/SignalNodes.h b/include/react/detail/graph/SignalNodes.h index 607746ea..268faf7c 100644 --- a/include/react/detail/graph/SignalNodes.h +++ b/include/react/detail/graph/SignalNodes.h @@ -308,6 +308,9 @@ class SignalLinkNode : public SignalNode ~SignalLinkNode() { + auto& linkCache = GetGraphPtr()->GetLinkCache(); + linkCache.Erase(this); + this->UnregisterMe(); } From 32fe91e6bcaa01556ddde119e5fc70e2c5f65756 Mon Sep 17 00:00:00 2001 From: schlangster Date: Mon, 23 Jan 2017 20:37:48 +0100 Subject: [PATCH 51/75] progress --- include/react/Group.h | 6 +- include/react/common/Containers.h | 267 +++++---------------- include/react/detail/graph/PropagationST.h | 5 +- include/react/engine/PulsecountEngine.h | 151 ------------ include/react/engine/SubtreeEngine.h | 198 --------------- include/react/engine/ToposortEngine.h | 214 ----------------- include/react/logging/EventLog.h | 100 -------- include/react/logging/EventRecords.h | 263 -------------------- include/react/logging/Logging.h | 31 --- project/msvc/CppReact.vcxproj | 3 - project/msvc/CppReact.vcxproj.filters | 12 - 11 files changed, 71 insertions(+), 1179 deletions(-) delete mode 100644 include/react/engine/PulsecountEngine.h delete mode 100644 include/react/engine/SubtreeEngine.h delete mode 100644 include/react/engine/ToposortEngine.h delete mode 100644 include/react/logging/EventLog.h delete mode 100644 include/react/logging/EventRecords.h delete mode 100644 include/react/logging/Logging.h diff --git a/include/react/Group.h b/include/react/Group.h index d68526df..dd62b012 100644 --- a/include/react/Group.h +++ b/include/react/Group.h @@ -65,9 +65,9 @@ class TransactionStatus public: // Default ctor - inline TransactionStatus() : + TransactionStatus() : statePtr_( StateT::Create() ) - {} + { } // Move ctor TransactionStatus(TransactionStatus&& other) : @@ -91,7 +91,7 @@ class TransactionStatus TransactionStatus(const TransactionStatus&) = delete; TransactionStatus& operator=(const TransactionStatus&) = delete; - inline void Wait() + void Wait() { assert(statePtr_.Get() != nullptr); statePtr_->Wait(); diff --git a/include/react/common/Containers.h b/include/react/common/Containers.h index a03257db..79980acf 100644 --- a/include/react/common/Containers.h +++ b/include/react/common/Containers.h @@ -14,59 +14,41 @@ #include #include #include +#include #include -#include /***************************************/ REACT_IMPL_BEGIN /**************************************/ -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// EnumFlags -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -class EnumFlags -{ -public: - using FlagsT = typename std::underlying_type::type; - - template - void Set() { flags_ |= 1 << x; } - - template - void Clear() { flags_ &= ~(1 << x); } - - template - bool Test() const { return (flags_ & (1 << x)) != 0; } - -private: - FlagsT flags_ = 0; -}; - - /////////////////////////////////////////////////////////////////////////////////////////////////// /// IndexMap /////////////////////////////////////////////////////////////////////////////////////////////////// template -class IndexMap +class IndexedStorage { static const size_t initial_capacity = 8; static const size_t grow_factor = 2; + using StorageType = typename std::aligned_storage::type; + public: using ValueType = T; - IndexMap() = default; + IndexedStorage() = default; - IndexMap(const IndexMap&) = default; - IndexMap& operator=(const IndexMap&) = default; + IndexedStorage(IndexedStorage&&) = default; + IndexedStorage& operator=(IndexedStorage&&) = default; - IndexMap(IndexMap&&) = default; - IndexMap& operator=(IndexMap&&) = default; + IndexedStorage(const IndexedStorage&) = delete; + IndexedStorage& operator=(const IndexedStorage&) = delete; + + ~IndexedStorage() + { Reset(); } T& operator[](size_t index) - { return data_[index]; } + { return reinterpret_cast(data_[index]); } const T& operator[](size_t index) const - { return data_[index]; } + { return reinterpret_cast(data_[index]); } size_t Insert(T value) { @@ -85,61 +67,73 @@ class IndexMap } } - void Remove(size_t index) + void Erase(size_t index) { - for (size_t index : freeIndices_) - data_[index].~T(); + // If we erased something other than the last element, save in free index list. + if (index != (size_ - 1)) + { + freeIndices_[freeSize_++] = index; + } + + reinterpret_cast(data_[index]).~T(); --size_; - freeIndices_.push_back(index); } void Clear() { - // Sort free indexes so we can remove check for them in linear time - std::sort(freeIndices_.begin(), freeIndices_.end()); + // Sort free indexes so we can remove check for them in linear time. + std::sort(&freeIndices_[0], &freeIndices_[freeSize_]); - const size_t totalSize = size_ + freeIndices_.size(); - size_t i = 0; + const size_t totalSize = size_ + freeSize_; + size_t index = 0; - // Skip over free indices - for (auto freeIndex : freeIndices_) + // Skip over free indices. + for (size_t j = 0; j < freeSize_; ++j) { - for (; i < totalSize; ++i) + for (; index < totalSize; ++index) { - if (i == freeIndex) + if (j == freeIndex_) + { + ++index; break; + } else - data_[i].~T(); + { + data_[index].~T(); + } } } // Rest - for (; i < totalSize; ++i) - data_[i].~T(); + for (; index < totalSize; ++index) + data_[index].~T(); size_ = 0; - freeIndices_.clear(); + freeList_ = 0; } void Reset() { Clear(); - capacity_ = 0; - delete[] data_; + data_.reset(); + freeIndices_.reset(); - freeIndices_.shrink_to_fit(); + capacity_ = 0; } - ~IndexMap() - { Reset(); } - private: + T& GetDataAt(size_t index) + { return reinterpret_cast(data_[index]); } + + T& GetDataAt(size_t index) const + { return reinterpret_cast(data_[index]); } + bool IsAtFullCapacity() const { return capacity_ == size_; } bool HasFreeIndices() const - { return !freeIndices_.empty(); } + { return freeSize_ > 0; } size_t CalcNextCapacity() const { return capacity_ == 0? initial_capacity : capacity_ * grow_factor; } @@ -148,20 +142,23 @@ class IndexMap { // Allocate new storage size_t newCapacity = CalcNextCapacity(); - T* newData = new T[newCapacity]; + + std::unique_ptr newData{ new StorageType[newCapacity] }; + std::unique_ptr newFreeList{ new size_t[newCapacity] }; // Move data to new storage - for (size_t i = 0; i < size_; ++i) + for (size_t i = 0; i < capacity_; ++i) { - new (&newData[i]) T(std::move(data_[i])); - data_[i].~T(); + new (reinterpret_cast(&newData[i])) T{ std::move(reinterpret_cast(data_[i])) }; + reinterpret_cast(data_[i]).~T(); } - - delete[] data_; + + // Free list is empty if we are at max capacity anyway // Use new storage - data_ = newData; - capacity_ = newCapacity; + data_ = std::move(newData); + freeIndices_ = std::move(newFreeList); + capacity_ = newCapacity; } size_t InsertAtBack(T&& value) @@ -172,153 +169,19 @@ class IndexMap size_t InsertAtFreeIndex(T&& value) { - size_t nextFreeIndex = freeIndices_.back(); - freeIndices_.pop_back(); - + size_t nextFreeIndex = freeIndices_[--freeSize_]; new (&data_[nextFreeIndex]) T(std::move(value)); ++size_; return nextFreeIndex; } - T* data_ = nullptr; + std::unique_ptr data_; + std::unique_ptr freeIndices_; + size_t size_ = 0; + size_t freeSize_ = 0; size_t capacity_ = 0; - - std::vector freeIndices_; -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// NodeVector -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -class NodeVector -{ -private: - typedef std::vector DataT; - -public: - void Add(TNode& node) - { - data_.push_back(&node); - } - - void Remove(const TNode& node) - { - data_.erase(std::find(data_.begin(), data_.end(), &node)); - } - - typedef typename DataT::iterator iterator; - typedef typename DataT::const_iterator const_iterator; - - iterator begin() { return data_.begin(); } - iterator end() { return data_.end(); } - - const_iterator begin() const { return data_.begin(); } - const_iterator end() const { return data_.end(); } - -private: - DataT data_; -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// NodeBuffer -/////////////////////////////////////////////////////////////////////////////////////////////////// -struct SplitTag {}; - -template -class NodeBuffer -{ -public: - using DataT = std::array; - using iterator = typename DataT::iterator; - using const_iterator = typename DataT::const_iterator; - - static const size_t split_size = N / 2; - - NodeBuffer() : - size_( 0 ), - front_( nodes_.begin() ), - back_( nodes_.begin() ) - {} - - NodeBuffer(T* node) : - size_( 1 ), - front_( nodes_.begin() ), - back_( nodes_.begin() + 1 ) - { - nodes_[0] = node; - } - - template - NodeBuffer(TInput srcBegin, TInput srcEnd) : - size_( std::distance(srcBegin, srcEnd) ), // parentheses to allow narrowing conversion - front_( nodes_.begin() ), - back_( size_ != N ? nodes_.begin() + size_ : nodes_.begin() ) - { - std::copy(srcBegin, srcEnd, front_); - } - - // Other must be full - NodeBuffer(NodeBuffer& other, SplitTag) : - size_( split_size ), - front_( nodes_.begin() ), - back_( nodes_.begin() ) - { - for (auto i=0; i nodeData_; + TopoQueue scheduledNodes_; - IndexMap nodeData_; std::vector changedInputs_; LinkOutputMap scheduledLinkOutputs_; @@ -232,7 +233,7 @@ NodeId ReactiveGraph::RegisterNode(IReactiveNode* nodePtr, NodeCategory category void ReactiveGraph::UnregisterNode(NodeId nodeId) { - nodeData_.Remove(nodeId); + nodeData_.Erase(nodeId); } void ReactiveGraph::OnNodeAttach(NodeId nodeId, NodeId parentId) diff --git a/include/react/engine/PulsecountEngine.h b/include/react/engine/PulsecountEngine.h deleted file mode 100644 index 78999c6f..00000000 --- a/include/react/engine/PulsecountEngine.h +++ /dev/null @@ -1,151 +0,0 @@ - -// Copyright Sebastian Jeckel 2016. -// 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) - -#ifndef REACT_DETAIL_ENGINE_PULSECOUNTENGINE_H_INCLUDED -#define REACT_DETAIL_ENGINE_PULSECOUNTENGINE_H_INCLUDED - -#pragma once - -#if 0 - -#include "react/detail/Defs.h" - -#include -#include -#include - -#include "tbb/task_group.h" -#include "tbb/spin_rw_mutex.h" -#include "tbb/task.h" - -#include "react/common/Containers.h" -#include "react/common/Types.h" -#include "react/detail/EngineBase.h" - -/***************************************/ REACT_IMPL_BEGIN /**************************************/ -namespace pulsecount { - -using std::atomic; -using std::vector; - -using tbb::task; -using tbb::empty_task; -using tbb::spin_rw_mutex; -using tbb::task_list; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Turn -/////////////////////////////////////////////////////////////////////////////////////////////////// -class Turn : public TurnBase -{ -public: - Turn(TurnIdT id, TransactionFlagsT flags); -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Node -/////////////////////////////////////////////////////////////////////////////////////////////////// -enum class ENodeMark -{ - unmarked, - visited, - should_update -}; - -enum class ENodeState -{ - unchanged, - changed, - dyn_defer, - dyn_repeat -}; - -class Node : public IReactiveNode -{ -public: - using ShiftMutexT = spin_rw_mutex; - - inline void IncCounter() { counter_.fetch_add(1, std::memory_order_relaxed); } - inline bool DecCounter() { return counter_.fetch_sub(1, std::memory_order_relaxed) > 1; } - inline void SetCounter(int c) { counter_.store(c, std::memory_order_relaxed); } - - inline ENodeMark Mark() const - { - return mark_.load(std::memory_order_relaxed); - } - - inline void SetMark(ENodeMark mark) - { - mark_.store(mark, std::memory_order_relaxed); - } - - inline bool ExchangeMark(ENodeMark mark) - { - return mark_.exchange(mark, std::memory_order_relaxed) != mark; - } - - ShiftMutexT ShiftMutex; - NodeVector Successors; - - ENodeState State = ENodeState::unchanged; - -private: - atomic counter_ { 0 }; - atomic mark_ { ENodeMark::unmarked }; -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// EngineBase -/////////////////////////////////////////////////////////////////////////////////////////////////// -class EngineBase : public IReactiveEngine -{ -public: - using NodeShiftMutexT = Node::ShiftMutexT; - using NodeVectT = vector; - - void OnNodeAttach(Node& node, Node& parent); - void OnNodeDetach(Node& node, Node& parent); - - void OnInputChange(Node& node, Turn& turn); - void Propagate(Turn& turn); - - void OnNodePulse(Node& node, Turn& turn); - void OnNodeIdlePulse(Node& node, Turn& turn); - - void OnDynamicNodeAttach(Node& node, Node& parent, Turn& turn); - void OnDynamicNodeDetach(Node& node, Node& parent, Turn& turn); - -private: - NodeVectT changedInputs_; - empty_task& rootTask_ = *new(task::allocate_root()) empty_task; - task_list spawnList_; -}; - -} // ~namespace pulsecount -/****************************************/ REACT_IMPL_END /***************************************/ - -/*****************************************/ REACT_BEGIN /*****************************************/ - -template -class PulsecountEngine; - -template <> -class PulsecountEngine : - public REACT_IMPL::pulsecount::EngineBase -{}; - -/******************************************/ REACT_END /******************************************/ - -/***************************************/ REACT_IMPL_BEGIN /**************************************/ - -template <> -struct NodeUpdateTimerEnabled> : std::true_type {}; - -/****************************************/ REACT_IMPL_END /***************************************/ - -#endif // REACT_DETAIL_ENGINE_PULSECOUNTENGINE_H_INCLUDED - -#endif \ No newline at end of file diff --git a/include/react/engine/SubtreeEngine.h b/include/react/engine/SubtreeEngine.h deleted file mode 100644 index 447c1184..00000000 --- a/include/react/engine/SubtreeEngine.h +++ /dev/null @@ -1,198 +0,0 @@ - -// Copyright Sebastian Jeckel 2016. -// 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) - -#if 0 - -#ifndef REACT_DETAIL_ENGINE_SUBTREEENGINE_H_INCLUDED -#define REACT_DETAIL_ENGINE_SUBTREEENGINE_H_INCLUDED - -#pragma once - -#include "react/detail/Defs.h" - -#include -#include -#include - -#include "tbb/spin_rw_mutex.h" -#include "tbb/task.h" - -#include "react/common/Containers.h" -#include "react/common/TopoQueue.h" -#include "react/common/Types.h" -#include "react/detail/EngineBase.h" - -/***************************************/ REACT_IMPL_BEGIN /**************************************/ -namespace subtree { - -using std::atomic; -using std::vector; - -using tbb::task; -using tbb::empty_task; -using tbb::task_list; -using tbb::spin_rw_mutex; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Turn -/////////////////////////////////////////////////////////////////////////////////////////////////// -class Turn : public TurnBase -{ -public: - Turn(TurnIdT id, TransactionFlagsT flags); -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Node -/////////////////////////////////////////////////////////////////////////////////////////////////// -class Node : public IReactiveNode -{ -public: - using ShiftMutexT = spin_rw_mutex; - - inline bool IsQueued() const { return flags_.Test(); } - inline void SetQueuedFlag() { flags_.Set(); } - inline void ClearQueuedFlag() { flags_.Clear(); } - - inline bool IsMarked() const { return flags_.Test(); } - inline void SetMarkedFlag() { flags_.Set(); } - inline void ClearMarkedFlag() { flags_.Clear(); } - - inline bool IsChanged() const { return flags_.Test(); } - inline void SetChangedFlag() { flags_.Set(); } - inline void ClearChangedFlag() { flags_.Clear(); } - - inline bool IsDeferred() const { return flags_.Test(); } - inline void SetDeferredFlag() { flags_.Set(); } - inline void ClearDeferredFlag() { flags_.Clear(); } - - inline bool IsRepeated() const { return flags_.Test(); } - inline void SetRepeatedFlag() { flags_.Set(); } - inline void ClearRepeatedFlag() { flags_.Clear(); } - - inline bool IsInitial() const { return flags_.Test(); } - inline void SetInitialFlag() { flags_.Set(); } - inline void ClearInitialFlag() { flags_.Clear(); } - - inline bool IsRoot() const { return flags_.Test(); } - inline void SetRootFlag() { flags_.Set(); } - inline void ClearRootFlag() { flags_.Clear(); } - - inline bool ShouldUpdate() const { return shouldUpdate_.load(std::memory_order_relaxed); } - inline void SetShouldUpdate(bool b) { shouldUpdate_.store(b, std::memory_order_relaxed); } - - inline void SetReadyCount(int c) - { - readyCount_.store(c, std::memory_order_relaxed); - } - - inline bool IncReadyCount() - { - auto t = readyCount_.fetch_add(1, std::memory_order_relaxed); - return t < (WaitCount - 1); - } - - inline bool DecReadyCount() - { - return readyCount_.fetch_sub(1, std::memory_order_relaxed) > 1; - } - - NodeVector Successors; - ShiftMutexT ShiftMutex; - uint16_t Level = 0; - uint16_t NewLevel = 0; - uint16_t WaitCount = 0; - -private: - enum EFlags : uint16_t - { - flag_queued = 0, - flag_marked, - flag_changed, - flag_deferred, - flag_repeated, - flag_initial, - flag_root - }; - - EnumFlags flags_; - atomic readyCount_ { 0 }; - atomic shouldUpdate_ { false }; -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Functors -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -struct GetLevelFunctor -{ - int operator()(const T* x) const { return x->Level; } -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// EngineBase -/////////////////////////////////////////////////////////////////////////////////////////////////// -class EngineBase : public IReactiveEngine -{ -public: - using TopoQueueT = TopoQueue>; - using NodeShiftMutexT = Node::ShiftMutexT; - - void OnNodeAttach(Node& node, Node& parent); - void OnNodeDetach(Node& node, Node& parent); - - void OnInputChange(Node& node, Turn& turn); - void Propagate(Turn& turn); - - void OnNodePulse(Node& node, Turn& turn); - void OnNodeIdlePulse(Node& node, Turn& turn); - - void OnDynamicNodeAttach(Node& node, Node& parent, Turn& turn); - void OnDynamicNodeDetach(Node& node, Node& parent, Turn& turn); - -private: - void applyAsyncDynamicAttach(Node& node, Node& parent, Turn& turn); - void applyAsyncDynamicDetach(Node& node, Node& parent, Turn& turn); - - void invalidateSuccessors(Node& node); - void processChildren(Node& node, Turn& turn); - - void markSubtree(Node& root); - - TopoQueueT scheduledNodes_; - vector subtreeRoots_; - - empty_task& rootTask_ = *new(task::allocate_root()) empty_task; - task_list spawnList_; - - bool isInPhase2_ = false; -}; - -} // ~namespace subtree -/****************************************/ REACT_IMPL_END /***************************************/ - -/*****************************************/ REACT_BEGIN /*****************************************/ - -template -class SubtreeEngine; - -template <> -class SubtreeEngine : - public REACT_IMPL::subtree::EngineBase -{}; - -/******************************************/ REACT_END /******************************************/ - -/***************************************/ REACT_IMPL_BEGIN /**************************************/ - -template <> -struct NodeUpdateTimerEnabled> : std::true_type {}; - -/****************************************/ REACT_IMPL_END /***************************************/ - -#endif // REACT_DETAIL_ENGINE_SUBTREEENGINE_H_INCLUDED - -#endif \ No newline at end of file diff --git a/include/react/engine/ToposortEngine.h b/include/react/engine/ToposortEngine.h deleted file mode 100644 index 2575bbd9..00000000 --- a/include/react/engine/ToposortEngine.h +++ /dev/null @@ -1,214 +0,0 @@ - -// Copyright Sebastian Jeckel 2016. -// 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) - -#if 0 - -#ifndef REACT_DETAIL_ENGINE_TOPOSORTENGINE_H_INCLUDED -#define REACT_DETAIL_ENGINE_TOPOSORTENGINE_H_INCLUDED - -#pragma once - -#include "react/detail/Defs.h" - -#include -#include -#include -#include - -#include "tbb/concurrent_vector.h" -#include "tbb/spin_mutex.h" - -#include "react/common/Containers.h" -#include "react/common/TopoQueue.h" -#include "react/common/Types.h" -#include "react/detail/EngineBase.h" - -/***************************************/ REACT_IMPL_BEGIN /**************************************/ - -namespace toposort { - -using std::atomic; -using std::vector; -using tbb::concurrent_vector; -using tbb::spin_mutex; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Parameters -/////////////////////////////////////////////////////////////////////////////////////////////////// -static const uint min_weight = 1; -static const uint grain_size = 100; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// SeqNode -/////////////////////////////////////////////////////////////////////////////////////////////////// -class SeqNode : public IReactiveNode -{ -public: - int Level { 0 }; - int NewLevel { 0 }; - bool Queued { false }; - - NodeVector Successors; -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// ParNode -/////////////////////////////////////////////////////////////////////////////////////////////////// -class ParNode : public IReactiveNode -{ -public: - using InvalidateMutexT = spin_mutex; - - int Level { 0 }; - int NewLevel { 0 }; - atomic Collected { false }; - - NodeVector Successors; - InvalidateMutexT InvalidateMutex; -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// ShiftRequestData -/////////////////////////////////////////////////////////////////////////////////////////////////// -struct DynRequestData -{ - bool ShouldAttach; - ParNode* Node; - ParNode* Parent; -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// ExclusiveSeqTurn -/////////////////////////////////////////////////////////////////////////////////////////////////// -class SeqTurn : public TurnBase -{ -public: - SeqTurn(TurnIdT id, TransactionFlagsT flags); -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// ExclusiveParTurn -/////////////////////////////////////////////////////////////////////////////////////////////////// -class ParTurn : public TurnBase -{ -public: - ParTurn(TurnIdT id, TransactionFlagsT flags); -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Functors -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -struct GetLevelFunctor -{ - int operator()(const T* x) const { return x->Level; } -}; - -template -struct GetWeightFunctor -{ - uint operator()(T* x) const { return x->IsHeavyweight() ? grain_size : 1; } -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// EngineBase -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -class EngineBase : public IReactiveEngine -{ -public: - void OnNodeAttach(TNode& node, TNode& parent); - void OnNodeDetach(TNode& node, TNode& parent); - - void OnInputChange(TNode& node, TTurn& turn); - void OnNodePulse(TNode& node, TTurn& turn); - -protected: - virtual void processChildren(TNode& node, TTurn& turn) = 0; -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// SeqEngineBase -/////////////////////////////////////////////////////////////////////////////////////////////////// -class SeqEngineBase : public EngineBase -{ -public: - using TopoQueueT = TopoQueue>; - - void Propagate(SeqTurn& turn); - - void OnDynamicNodeAttach(SeqNode& node, SeqNode& parent, SeqTurn& turn); - void OnDynamicNodeDetach(SeqNode& node, SeqNode& parent, SeqTurn& turn); - -private: - void invalidateSuccessors(SeqNode& node); - - virtual void processChildren(SeqNode& node, SeqTurn& turn) override; - - TopoQueueT scheduledNodes_; -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// ParEngineBase -/////////////////////////////////////////////////////////////////////////////////////////////////// -class ParEngineBase : public EngineBase -{ -public: - using DynRequestVectT = concurrent_vector; - using TopoQueueT = ConcurrentTopoQueue - < - ParNode*, - grain_size, - GetLevelFunctor, - GetWeightFunctor - >; - - void Propagate(ParTurn& turn); - - void OnDynamicNodeAttach(ParNode& node, ParNode& parent, ParTurn& turn); - void OnDynamicNodeDetach(ParNode& node, ParNode& parent, ParTurn& turn); - -private: - void applyDynamicAttach(ParNode& node, ParNode& parent, ParTurn& turn); - void applyDynamicDetach(ParNode& node, ParNode& parent, ParTurn& turn); - - void invalidateSuccessors(ParNode& node); - - virtual void processChildren(ParNode& node, ParTurn& turn) override; - - TopoQueueT topoQueue_; - DynRequestVectT dynRequests_; -}; - -} // ~namespace toposort - -/****************************************/ REACT_IMPL_END /***************************************/ - -/*****************************************/ REACT_BEGIN /*****************************************/ - -template -class ToposortEngine; - -template <> class ToposortEngine : - public REACT_IMPL::toposort::SeqEngineBase -{}; - -template <> class ToposortEngine : - public REACT_IMPL::toposort::ParEngineBase -{}; - -/******************************************/ REACT_END /******************************************/ - -/***************************************/ REACT_IMPL_BEGIN /**************************************/ - -template <> -struct NodeUpdateTimerEnabled> : std::true_type {}; - -/****************************************/ REACT_IMPL_END /***************************************/ - -#endif // REACT_DETAIL_ENGINE_TOPOSORTENGINE_H_INCLUDED - -#endif \ No newline at end of file diff --git a/include/react/logging/EventLog.h b/include/react/logging/EventLog.h deleted file mode 100644 index 6b94277f..00000000 --- a/include/react/logging/EventLog.h +++ /dev/null @@ -1,100 +0,0 @@ - -// Copyright Sebastian Jeckel 2016. -// 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) - -#ifndef REACT_DETAIL_LOGGING_EVENTLOG_H_INCLUDED -#define REACT_DETAIL_LOGGING_EVENTLOG_H_INCLUDED - -#pragma once - -#include "react/detail/Defs.h" - -#include -#include -#include -#include -#include - -#include "tbb/concurrent_vector.h" - -#include "Logging.h" -#include "react/common/Types.h" - -/***************************************/ REACT_IMPL_BEGIN /**************************************/ - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// EventLog -/////////////////////////////////////////////////////////////////////////////////////////////////// -class EventLog -{ - using TimestampT = std::chrono::time_point; - - class Entry - { - public: - Entry(); - Entry(const Entry& other); - - explicit Entry(IEventRecord* ptr); - - Entry& operator=(Entry& rhs); - - inline const char* EventId() const - { - return data_->EventId(); - } - - inline const TimestampT& Time() const - { - return time_; - } - - inline bool operator<(const Entry& other) const - { - return time_ < other.time_; - } - - inline void Release() - { - delete data_; - } - - void Serialize(std::ostream& out, const TimestampT& startTime) const; - bool Equals(const Entry& other) const; - - private: - TimestampT time_; - IEventRecord* data_; - }; - -public: - - EventLog(); - ~EventLog(); - - void Print(); - void Write(std::ostream& out); - void Clear(); - - template - < - typename TEventRecord, - typename ... TArgs - > - void Append(TArgs ... args) - { - entries_.push_back(Entry(new TEventRecord(args ...))); - } - -private: - using LogEntriesT = tbb::concurrent_vector; - - LogEntriesT entries_; - TimestampT startTime_; -}; - -/****************************************/ REACT_IMPL_END /***************************************/ - -#endif // REACT_DETAIL_LOGGING_EVENTLOG_H_INCLUDED \ No newline at end of file diff --git a/include/react/logging/EventRecords.h b/include/react/logging/EventRecords.h deleted file mode 100644 index ea2359f5..00000000 --- a/include/react/logging/EventRecords.h +++ /dev/null @@ -1,263 +0,0 @@ - -// Copyright Sebastian Jeckel 2016. -// 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) - -#ifndef REACT_DETAIL_LOGGING_EVENTRECORDS_H_INCLUDED -#define REACT_DETAIL_LOGGING_EVENTRECORDS_H_INCLUDED - -#pragma once - -#include "react/detail/Defs.h" - -#include -#include -#include - -#include "Logging.h" -#include "react/common/Types.h" - -/***************************************/ REACT_IMPL_BEGIN /**************************************/ - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// NodeCreateEvent -/////////////////////////////////////////////////////////////////////////////////////////////////// -class NodeCreateEvent : public IEventRecord -{ -public: - NodeCreateEvent(ObjectId nodeId, const char* type); - - virtual const char* EventId() const { return "NodeCreate"; } - - virtual void Serialize(std::ostream& out) const; - -private: - ObjectId nodeId_; - const char * type_; -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// NodeDestroyEvent -/////////////////////////////////////////////////////////////////////////////////////////////////// -class NodeDestroyEvent : public IEventRecord -{ -public: - NodeDestroyEvent(ObjectId nodeId); - - virtual const char* EventId() const { return "NodeDestroy"; } - - virtual void Serialize(std::ostream& out) const; - -private: - ObjectId nodeId_; -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// NodeAttachEvent -/////////////////////////////////////////////////////////////////////////////////////////////////// -class NodeAttachEvent : public IEventRecord -{ -public: - NodeAttachEvent(ObjectId nodeId, ObjectId parentId); - - virtual const char* EventId() const { return "NodeAttach"; } - - virtual void Serialize(std::ostream& out) const; - -private: - ObjectId nodeId_; - ObjectId parentId_; -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// NodeDetachEvent -/////////////////////////////////////////////////////////////////////////////////////////////////// -class NodeDetachEvent : public IEventRecord -{ -public: - NodeDetachEvent(ObjectId nodeId, ObjectId parentId); - - virtual const char* EventId() const { return "NodeDetach"; } - - virtual void Serialize(std::ostream& out) const; - -private: - ObjectId nodeId_; - ObjectId parentId_; -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// InputNodeAdmissionEvent -/////////////////////////////////////////////////////////////////////////////////////////////////// -class InputNodeAdmissionEvent : public IEventRecord -{ -public: - InputNodeAdmissionEvent(ObjectId nodeId, int transactionId); - - virtual const char* EventId() const { return "InputNodeAdmission"; } - - virtual void Serialize(std::ostream& out) const; - -private: - ObjectId nodeId_; - int transactionId_; -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// NodePulseEvent -/////////////////////////////////////////////////////////////////////////////////////////////////// -class NodePulseEvent : public IEventRecord -{ -public: - NodePulseEvent(ObjectId nodeId, int transactionId); - - virtual const char* EventId() const { return "NodePulse"; } - - virtual void Serialize(std::ostream& out) const; - -private: - ObjectId nodeId_; - int transactionId_; -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// NodeIdlePulseEvent -/////////////////////////////////////////////////////////////////////////////////////////////////// -class NodeIdlePulseEvent : public IEventRecord -{ -public: - NodeIdlePulseEvent(ObjectId nodeId, int transactionId); - - virtual const char* EventId() const { return "NodeIdlePulse"; } - - virtual void Serialize(std::ostream& out) const; - -private: - ObjectId nodeId_; - int transactionId_; -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// DynamicNodeAttachEvent -/////////////////////////////////////////////////////////////////////////////////////////////////// -class DynamicNodeAttachEvent : public IEventRecord -{ -public: - DynamicNodeAttachEvent(ObjectId nodeId, ObjectId parentId, int transactionId); - - virtual const char* EventId() const { return "DynamicNodeAttach"; } - - virtual void Serialize(std::ostream& out) const; - -private: - ObjectId nodeId_; - ObjectId parentId_; - int transactionId_; -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// DynamicNodeDetachEvent -/////////////////////////////////////////////////////////////////////////////////////////////////// -class DynamicNodeDetachEvent : public IEventRecord -{ -public: - DynamicNodeDetachEvent(ObjectId nodeId, ObjectId parentId, int transactionId); - - virtual const char* EventId() const { return "DynamicNodeDetach"; } - - virtual void Serialize(std::ostream& out) const; - -private: - ObjectId nodeId_; - ObjectId parentId_; - int transactionId_; -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// NodeEvaluateBeginEvent -/////////////////////////////////////////////////////////////////////////////////////////////////// -class NodeEvaluateBeginEvent : public IEventRecord -{ -public: - NodeEvaluateBeginEvent(ObjectId nodeId, int transactionId); - - virtual const char* EventId() const { return "NodeEvaluateBegin"; } - - virtual void Serialize(std::ostream& out) const; - -private: - ObjectId nodeId_; - int transactionId_; - std::thread::id threadId_; -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// NodeEvaluateEndEvent -/////////////////////////////////////////////////////////////////////////////////////////////////// -class NodeEvaluateEndEvent : public IEventRecord -{ -public: - NodeEvaluateEndEvent(ObjectId nodeId, int transactionId); - - virtual const char* EventId() const { return "NodeEvaluateEnd"; } - - virtual void Serialize(std::ostream& out) const; - -private: - ObjectId nodeId_; - int transactionId_; - std::thread::id threadId_; -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// TransactionBeginEvent -/////////////////////////////////////////////////////////////////////////////////////////////////// -class TransactionBeginEvent : public IEventRecord -{ -public: - TransactionBeginEvent(int transactionId); - - virtual const char* EventId() const { return "TransactionBegin"; } - - virtual void Serialize(std::ostream& out) const; - -private: - int transactionId_; -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// TransactionEndEvent -/////////////////////////////////////////////////////////////////////////////////////////////////// -class TransactionEndEvent : public IEventRecord -{ -public: - TransactionEndEvent(int transactionId); - - virtual const char* EventId() const { return "TransactionEnd"; } - - virtual void Serialize(std::ostream& out) const; - -private: - int transactionId_; -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// UserBreakpointEvent -/////////////////////////////////////////////////////////////////////////////////////////////////// -class UserBreakpointEvent : public IEventRecord -{ -public: - UserBreakpointEvent(const char* name); - - virtual const char* EventId() const { return "UserBreakpoint"; } - - virtual void Serialize(std::ostream& out) const; - -private: - std::string name_; -}; - -/****************************************/ REACT_IMPL_END /***************************************/ - -#endif // REACT_DETAIL_LOGGING_EVENTRECORDS_H_INCLUDED \ No newline at end of file diff --git a/include/react/logging/Logging.h b/include/react/logging/Logging.h deleted file mode 100644 index 3f0aacd2..00000000 --- a/include/react/logging/Logging.h +++ /dev/null @@ -1,31 +0,0 @@ - -// Copyright Sebastian Jeckel 2016. -// 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) - -#ifndef REACT_DETAIL_LOGGING_LOGGING_H_INCLUDED -#define REACT_DETAIL_LOGGING_LOGGING_H_INCLUDED - -#pragma once - -#include "react/detail/Defs.h" - -#include - -/***************************************/ REACT_IMPL_BEGIN /**************************************/ - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// IEventRecord -/////////////////////////////////////////////////////////////////////////////////////////////////// -struct IEventRecord -{ - virtual ~IEventRecord() {} - - virtual const char* EventId() const = 0; - virtual void Serialize(std::ostream& out) const = 0; -}; - -/****************************************/ REACT_IMPL_END /***************************************/ - -#endif // REACT_DETAIL_LOGGING_LOGGING_H_INCLUDED \ No newline at end of file diff --git a/project/msvc/CppReact.vcxproj b/project/msvc/CppReact.vcxproj index ead65969..6b961f03 100644 --- a/project/msvc/CppReact.vcxproj +++ b/project/msvc/CppReact.vcxproj @@ -168,9 +168,6 @@ - - - diff --git a/project/msvc/CppReact.vcxproj.filters b/project/msvc/CppReact.vcxproj.filters index 76abe5da..c78bde77 100644 --- a/project/msvc/CppReact.vcxproj.filters +++ b/project/msvc/CppReact.vcxproj.filters @@ -19,9 +19,6 @@ {c7adc39d-d19e-4fe2-b945-332515717bc8} - - {6883dd62-b27e-4b11-9cc8-cbac096f4723} - {11a75126-8bfd-4693-be4b-4e06ab73450c} @@ -48,9 +45,6 @@ Header Files\common - - Header Files\engine - Header Files\detail @@ -72,15 +66,9 @@ Header Files\detail\graph - - Header Files\engine - Header Files\common - - Header Files\engine - Header Files\common From d0e5375b9e70cace84c4b2a9a97e8666a149cb69 Mon Sep 17 00:00:00 2001 From: schlangster Date: Tue, 24 Oct 2017 02:36:31 +0200 Subject: [PATCH 52/75] Progress dump. --- benchmarks/src/BenchmarkBase.h | 2 +- benchmarks/src/BenchmarkFanout.h | 2 +- benchmarks/src/BenchmarkGrid.h | 2 +- benchmarks/src/BenchmarkLifeSim.h | 2 +- benchmarks/src/BenchmarkRandom.h | 2 +- benchmarks/src/BenchmarkSequence.h | 2 +- benchmarks/src/Main.cpp | 52 +- examples/src/BasicAlgorithms.cpp | 2 +- examples/src/BasicComposition.cpp | 2 +- examples/src/BasicEvents.cpp | 2 +- examples/src/BasicObservers.cpp | 2 +- examples/src/BasicSignals.cpp | 2 +- examples/src/BasicSynchronization.cpp | 2 +- examples/src/Main.cpp | 7 +- include/react/API.h | 11 +- include/react/Algorithm.h | 87 +- include/react/Event.h | 172 +-- include/react/Group.h | 75 +- include/react/Observer.h | 79 +- include/react/Signal.h | 126 +-- include/react/common/Concurrency.h | 324 ------ include/react/common/RefCounting.h | 4 +- include/react/common/SourceIdSet.h | 4 +- include/react/common/Timing.h | 4 +- include/react/common/TopoQueue.h | 4 +- include/react/common/Types.h | 4 +- include/react/common/Util.h | 249 ----- include/react/common/expected.h | 218 ++++ include/react/common/optional.h | 70 ++ include/react/common/owned_ptr.h | 18 + include/react/common/ptrcache.h | 65 ++ .../react/common/{Containers.h => slotmap.h} | 40 +- include/react/common/syncpoint.h | 195 ++++ include/react/common/utility.h | 58 ++ include/react/detail/Defs.h | 9 +- include/react/detail/ReactiveInput.h | 983 ------------------ .../AlgorithmNodes.h => algorithm_nodes.h} | 162 +-- .../{graph/EventNodes.h => event_nodes.h} | 280 ++--- include/react/detail/graph/PropagationMT.h | 0 include/react/detail/graph/PropagationST.h | 500 --------- include/react/detail/graph_impl.h | 224 ++++ .../{IReactiveGraph.h => graph_interface.h} | 42 +- .../detail/{graph/GraphBase.h => node_base.h} | 40 +- .../ObserverNodes.h => observer_nodes.h} | 60 +- .../{graph/SignalNodes.h => signal_nodes.h} | 159 ++- project/msvc/CppReact.sln | 33 +- project/msvc/CppReact.vcxproj | 56 +- project/msvc/CppReact.vcxproj.filters | 91 +- project/msvc/CppReactBenchmark.vcxproj | 10 +- project/msvc/CppReactExample.vcxproj | 10 +- project/msvc/CppReactTest.vcxproj | 44 +- project/msvc/CppReactTest.vcxproj.filters | 45 +- project/msvc/Example_BasicAlgorithms.vcxproj | 10 +- project/msvc/Example_BasicComposition.vcxproj | 10 +- project/msvc/Example_BasicEvents.vcxproj | 10 +- project/msvc/Example_BasicObservers.vcxproj | 10 +- project/msvc/Example_BasicSignals.vcxproj | 10 +- .../msvc/Example_BasicSynchronization.vcxproj | 10 +- src/detail/graph_impl.cpp | 248 +++++ src/engine/PulsecountEngine.cpp | 6 +- src/engine/SubtreeEngine.cpp | 10 +- src/engine/ToposortEngine.cpp | 14 +- src/logging/EventLog.cpp | 84 -- src/logging/EventRecords.cpp | 210 ---- tests/src/EventStreamTest.cpp | 29 - tests/src/EventStreamTest.h | 2 +- tests/src/EventStreamTestQ.cpp | 2 +- tests/src/MoveTest.cpp | 11 +- tests/src/MoveTest.h | 2 +- tests/src/ObserverTest.cpp | 19 +- tests/src/ObserverTest.h | 2 +- tests/src/ObserverTestQ.cpp | 2 +- tests/src/OperationsTest.cpp | 19 +- tests/src/OperationsTest.h | 2 +- tests/src/OperationsTestQ.cpp | 2 +- tests/src/ParallelizationTest.cpp | 19 +- tests/src/ParallelizationTest.h | 2 +- tests/src/SignalTest.cpp | 20 +- tests/src/SignalTest.h | 2 +- tests/src/SignalTestQ.cpp | 2 +- tests/src/TestUtil.h | 2 +- tests/src/TransactionTest.cpp | 19 +- tests/src/TransactionTest.h | 2 +- tests/src/common_tests.cpp | 132 +++ tests/src/event_tests.cpp | 219 ++++ 85 files changed, 2205 insertions(+), 3576 deletions(-) delete mode 100644 include/react/common/Concurrency.h delete mode 100644 include/react/common/Util.h create mode 100644 include/react/common/expected.h create mode 100644 include/react/common/optional.h create mode 100644 include/react/common/owned_ptr.h create mode 100644 include/react/common/ptrcache.h rename include/react/common/{Containers.h => slotmap.h} (82%) create mode 100644 include/react/common/syncpoint.h create mode 100644 include/react/common/utility.h delete mode 100644 include/react/detail/ReactiveInput.h rename include/react/detail/{graph/AlgorithmNodes.h => algorithm_nodes.h} (68%) rename include/react/detail/{graph/EventNodes.h => event_nodes.h} (66%) delete mode 100644 include/react/detail/graph/PropagationMT.h delete mode 100644 include/react/detail/graph/PropagationST.h create mode 100644 include/react/detail/graph_impl.h rename include/react/detail/{IReactiveGraph.h => graph_interface.h} (63%) rename include/react/detail/{graph/GraphBase.h => node_base.h} (65%) rename include/react/detail/{graph/ObserverNodes.h => observer_nodes.h} (69%) rename include/react/detail/{graph/SignalNodes.h => signal_nodes.h} (74%) create mode 100644 src/detail/graph_impl.cpp delete mode 100644 src/logging/EventLog.cpp delete mode 100644 src/logging/EventRecords.cpp delete mode 100644 tests/src/EventStreamTest.cpp create mode 100644 tests/src/common_tests.cpp create mode 100644 tests/src/event_tests.cpp diff --git a/benchmarks/src/BenchmarkBase.h b/benchmarks/src/BenchmarkBase.h index 7df36bbe..d27d64b1 100644 --- a/benchmarks/src/BenchmarkBase.h +++ b/benchmarks/src/BenchmarkBase.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2016. +// Copyright Sebastian Jeckel 2017. // 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) diff --git a/benchmarks/src/BenchmarkFanout.h b/benchmarks/src/BenchmarkFanout.h index 672b5f7c..a4855d0f 100644 --- a/benchmarks/src/BenchmarkFanout.h +++ b/benchmarks/src/BenchmarkFanout.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2016. +// Copyright Sebastian Jeckel 2017. // 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) diff --git a/benchmarks/src/BenchmarkGrid.h b/benchmarks/src/BenchmarkGrid.h index d7ed0bb8..8f17d6f2 100644 --- a/benchmarks/src/BenchmarkGrid.h +++ b/benchmarks/src/BenchmarkGrid.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2016. +// Copyright Sebastian Jeckel 2017. // 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) diff --git a/benchmarks/src/BenchmarkLifeSim.h b/benchmarks/src/BenchmarkLifeSim.h index 6521f2d4..2511882d 100644 --- a/benchmarks/src/BenchmarkLifeSim.h +++ b/benchmarks/src/BenchmarkLifeSim.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2016. +// Copyright Sebastian Jeckel 2017. // 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) diff --git a/benchmarks/src/BenchmarkRandom.h b/benchmarks/src/BenchmarkRandom.h index e3ffe9ef..cec422da 100644 --- a/benchmarks/src/BenchmarkRandom.h +++ b/benchmarks/src/BenchmarkRandom.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2016. +// Copyright Sebastian Jeckel 2017. // 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) diff --git a/benchmarks/src/BenchmarkSequence.h b/benchmarks/src/BenchmarkSequence.h index bf87bc41..705e8f58 100644 --- a/benchmarks/src/BenchmarkSequence.h +++ b/benchmarks/src/BenchmarkSequence.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2016. +// Copyright Sebastian Jeckel 2017. // 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) diff --git a/benchmarks/src/Main.cpp b/benchmarks/src/Main.cpp index 2af96fdd..bc42b726 100644 --- a/benchmarks/src/Main.cpp +++ b/benchmarks/src/Main.cpp @@ -1,17 +1,17 @@ -// Copyright Sebastian Jeckel 2016. +// Copyright Sebastian Jeckel 2017. // 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) //#define REACT_ENABLE_LOGGING - -#include "tbb/tick_count.h" -#include "tbb/tbbmalloc_proxy.h" +#if 0 +//#include "tbb/tick_count.h" +//#include "tbb/tbbmalloc_proxy.h" //#include "ittnotify.h" -#include "BenchmarkGrid.h" +/*#include "BenchmarkGrid.h" #include "BenchmarkRandom.h" #include "BenchmarkFanout.h" #include "BenchmarkSequence.h" @@ -20,12 +20,12 @@ #include "react/Group.h" #include "react/Signal.h" #include "react/Algorithm.h" -#include "react/common/Util.h" +#include "react/common/Util.h"*/ /////////////////////////////////////////////////////////////////////////////////////////////////// namespace { -using namespace react; +//using namespace react; /*void runBenchmarkGrid(std::ostream& out) { @@ -198,7 +198,7 @@ void debugBenchmarks() void profileBenchmark() { - RUN_BENCHMARK(std::cout, 3, Benchmark_Grid, BenchmarkParams_Grid(100, 10000)); + //RUN_BENCHMARK(std::cout, 3, Benchmark_Grid, BenchmarkParams_Grid(100, 10000)); //RUN_BENCHMARK(std::cout, 1, Benchmark_Grid, BenchmarkParams_Grid(30, 10000), //SourceSetDomain); @@ -217,5 +217,39 @@ int main() { //runBenchmarks(); //debugBenchmarks(); - profileBenchmark(); + //profileBenchmark(); + + +} + +#endif + +#include "react/common/expected.h" +#include "react/signal.h" +#include "react/event.h" +#include "react/algorithm.h" +#include + +#define unwind_on_error(x) if (!x) return UnwindExpected(std::move(x)); + +using namespace react; + + +int main() +{ + Group g; + + VarSignal t1(g); + VarSignal t2(g); + + EventSource e1(g); + EventSource e2(g); + + auto h1 = Hold(1, e1); + auto h2 = Hold(2, e2); + + auto m1 = Monitor(t1); + auto it1 = Iterate(10, [] (EventRange evnts, int b) { return b; }, e1); + + return 0; } \ No newline at end of file diff --git a/examples/src/BasicAlgorithms.cpp b/examples/src/BasicAlgorithms.cpp index c2c5d123..93235700 100644 --- a/examples/src/BasicAlgorithms.cpp +++ b/examples/src/BasicAlgorithms.cpp @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2016. +// Copyright Sebastian Jeckel 2017. // 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) diff --git a/examples/src/BasicComposition.cpp b/examples/src/BasicComposition.cpp index d5354bae..e2fbf3b1 100644 --- a/examples/src/BasicComposition.cpp +++ b/examples/src/BasicComposition.cpp @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2016. +// Copyright Sebastian Jeckel 2017. // 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) diff --git a/examples/src/BasicEvents.cpp b/examples/src/BasicEvents.cpp index da3fa4f2..53e97984 100644 --- a/examples/src/BasicEvents.cpp +++ b/examples/src/BasicEvents.cpp @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2016. +// Copyright Sebastian Jeckel 2017. // 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) diff --git a/examples/src/BasicObservers.cpp b/examples/src/BasicObservers.cpp index fede6fd0..8eb03b81 100644 --- a/examples/src/BasicObservers.cpp +++ b/examples/src/BasicObservers.cpp @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2016. +// Copyright Sebastian Jeckel 2017. // 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) diff --git a/examples/src/BasicSignals.cpp b/examples/src/BasicSignals.cpp index a8b6a60a..749116c8 100644 --- a/examples/src/BasicSignals.cpp +++ b/examples/src/BasicSignals.cpp @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2016. +// Copyright Sebastian Jeckel 2017. // 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) diff --git a/examples/src/BasicSynchronization.cpp b/examples/src/BasicSynchronization.cpp index 8eacfa6e..701b5001 100644 --- a/examples/src/BasicSynchronization.cpp +++ b/examples/src/BasicSynchronization.cpp @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2016. +// Copyright Sebastian Jeckel 2017. // 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) diff --git a/examples/src/Main.cpp b/examples/src/Main.cpp index 5720dcf1..3d3bb8e4 100644 --- a/examples/src/Main.cpp +++ b/examples/src/Main.cpp @@ -15,6 +15,8 @@ #include "react/Algorithm.h" #include "react/Observer.h" +#include "react/common/expected.h" + using namespace react; template @@ -38,9 +40,6 @@ class GridGraphGenerator void Generate(const Group& group) { - assert(inputSignals.size() >= 1); - assert(widths.size() >= 1); - SignalVectType buf1 = std::move(inputSignals); SignalVectType buf2; @@ -366,6 +365,8 @@ int main() std::this_thread::sleep_for(std::chrono::seconds(5)); + Expected x; + return 0; } diff --git a/include/react/API.h b/include/react/API.h index da892da8..3e20d5bb 100644 --- a/include/react/API.h +++ b/include/react/API.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2016. +// Copyright Sebastian Jeckel 2017. // 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) @@ -9,8 +9,8 @@ #pragma once -#include "react/detail/Defs.h" -#include "react/common/Util.h" +#include "react/detail/defs.h" +#include "react/common/utility.h" /*****************************************/ REACT_BEGIN /*****************************************/ @@ -26,8 +26,9 @@ enum class WeightHint enum class TransactionFlags { - none = 0, - allow_merging = 1 << 1 + none = 0, + allow_merging = 1 << 1, + sync_linked = 1 << 2 }; REACT_DEFINE_BITMASK_OPERATORS(TransactionFlags) diff --git a/include/react/Algorithm.h b/include/react/Algorithm.h index babc4c8b..e149b491 100644 --- a/include/react/Algorithm.h +++ b/include/react/Algorithm.h @@ -9,28 +9,32 @@ #pragma once -#include "react/detail/Defs.h" +#include "react/detail/defs.h" #include #include #include #include "react/API.h" -#include "react/detail/graph/AlgorithmNodes.h" +#include "react/detail/algorithm_nodes.h" -#include "Event.h" -#include "Signal.h" +#include "react/event.h" +#include "react/signal.h" /*****************************************/ REACT_BEGIN /*****************************************/ /////////////////////////////////////////////////////////////////////////////////////////////////// -/// Hold - Hold the most recent event in a signal +/// Hold the most recent event in a signal /////////////////////////////////////////////////////////////////////////////////////////////////// template auto Hold(const Group& group, T&& initialValue, const Event& evnt) -> Signal { using REACT_IMPL::HoldNode; - return Signal::CreateWithNode>(group, std::forward(initialValue), SameGroupOrLink(group, evnt)); + using REACT_IMPL::SameGroupOrLink; + using REACT_IMPL::CreateWrappedNode; + + return CreateWrappedNode, HoldNode>( + group, std::forward(initialValue), SameGroupOrLink(group, evnt)); } template @@ -38,13 +42,17 @@ auto Hold(T&& initialValue, const Event& evnt) -> Signal { return Hold(evnt.GetGroup(), std::forward(initialValue), evnt); } /////////////////////////////////////////////////////////////////////////////////////////////////// -/// Monitor - Emits value changes of target signal +/// Emits value changes of target signal. /////////////////////////////////////////////////////////////////////////////////////////////////// template auto Monitor(const Group& group, const Signal& signal) -> Event { using REACT_IMPL::MonitorNode; - return Event::CreateWithNode>(group, SameGroupOrLink(group, signal)); + using REACT_IMPL::SameGroupOrLink; + using REACT_IMPL::CreateWrappedNode; + + return CreateWrappedNode, MonitorNode>( + group, SameGroupOrLink(group, signal)); } template @@ -58,22 +66,38 @@ template auto Iterate(const Group& group, T&& initialValue, F&& func, const Event& evnt) -> Signal { using REACT_IMPL::IterateNode; + using REACT_IMPL::IsCallableWith; + using REACT_IMPL::SameGroupOrLink; + using REACT_IMPL::CreateWrappedNode; + + using FuncType = typename std::decay::type; + + return CreateWrappedNode, IterateNode>( + group, std::forward(initialValue), std::forward(func), SameGroupOrLink(group, evnt)); +} + +template +auto IterateByRef(const Group& group, T&& initialValue, F&& func, const Event& evnt) -> Signal +{ using REACT_IMPL::IterateByRefNode; using REACT_IMPL::IsCallableWith; + using REACT_IMPL::SameGroupOrLink; + using REACT_IMPL::CreateWrappedNode; using FuncType = typename std::decay::type; - using IterNodeType = typename std::conditional< - IsCallableWith,S>::value, - IterateNode, - IterateByRefNode>::type; - return Signal::CreateWithNode(group, std::forward(initialValue), std::forward(func), SameGroupOrLink(group, evnt)); + return CreateWrappedNode, IterateByRefNode>( + group, std::forward(initialValue), std::forward(func), SameGroupOrLink(group, evnt)); } template auto Iterate(T&& initialValue, F&& func, const Event& evnt) -> Signal { return Iterate(evnt.GetGroup(), std::forward(initialValue), std::forward(func), evnt); } +template +auto IterateByRef(T&& initialValue, F&& func, const Event& evnt) -> Signal + { return IterateByRef(evnt.GetGroup(), std::forward(initialValue), std::forward(func), evnt); } + /////////////////////////////////////////////////////////////////////////////////////////////////// /// Iterate - Synced /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -81,16 +105,27 @@ template auto Iterate(const Group& group, T&& initialValue, F&& func, const Event& evnt, const Signal& ... signals) -> Signal { using REACT_IMPL::SyncedIterateNode; + using REACT_IMPL::IsCallableWith; + using REACT_IMPL::SameGroupOrLink; + using REACT_IMPL::CreateWrappedNode; + + using FuncType = typename std::decay::type; + + return CreateWrappedNode, SyncedIterateNode>( + group, std::forward(initialValue), std::forward(func), SameGroupOrLink(group, evnt), SameGroupOrLink(group, signals) ...); +} + +template +auto IterateByRef(const Group& group, T&& initialValue, F&& func, const Event& evnt, const Signal& ... signals) -> Signal +{ using REACT_IMPL::SyncedIterateByRefNode; using REACT_IMPL::IsCallableWith; + using REACT_IMPL::SameGroupOrLink; + using REACT_IMPL::CreateWrappedNode; using FuncType = typename std::decay::type; - using IterNodeType = typename std::conditional< - IsCallableWith, S, Us ...>::value, - SyncedIterateNode, - SyncedIterateByRefNode>::type; - return Signal::CreateWithNode( + return CreateWrappedNode, SyncedIterateByRefNode>( group, std::forward(initialValue), std::forward(func), SameGroupOrLink(group, evnt), SameGroupOrLink(group, signals) ...); } @@ -98,6 +133,10 @@ template auto Iterate(T&& initialValue, F&& func, const Event& evnt, const Signal& ... signals) -> Signal { return Iterate(evnt.GetGroup(), std::forward(initialValue), std::forward(func), evnt, signals ...); } +template +auto IterateByRef(T&& initialValue, F&& func, const Event& evnt, const Signal& ... signals) -> Signal + { return IterateByRef(evnt.GetGroup(), std::forward(initialValue), std::forward(func), evnt, signals ...); } + /////////////////////////////////////////////////////////////////////////////////////////////////// /// Snapshot - Sets signal value to value of other signal when event is received /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -105,7 +144,11 @@ template auto Snapshot(const Group& group, const Signal& signal, const Event& evnt) -> Signal { using REACT_IMPL::SnapshotNode; - return Signal::CreateWithNode>(group, SameGroupOrLink(group, signal), SameGroupOrLink(group, evnt)); + using REACT_IMPL::SameGroupOrLink; + using REACT_IMPL::CreateWrappedNode; + + return CreateWrappedNode, SnapshotNode>( + group, SameGroupOrLink(group, signal), SameGroupOrLink(group, evnt)); } template @@ -119,7 +162,11 @@ template auto Pulse(const Group& group, const Signal& signal, const Event& evnt) -> Event { using REACT_IMPL::PulseNode; - return Event::CreateWithNode>(group, SameGroupOrLink(group, signal), SameGroupOrLink(group, evnt)); + using REACT_IMPL::SameGroupOrLink; + using REACT_IMPL::CreateWrappedNode; + + return CreateWrappedNode, PulseNode>( + group, SameGroupOrLink(group, signal), SameGroupOrLink(group, evnt)); } template diff --git a/include/react/Event.h b/include/react/Event.h index 5d97dfff..ff4a0a17 100644 --- a/include/react/Event.h +++ b/include/react/Event.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2016. +// Copyright Sebastian Jeckel 2017. // 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) @@ -9,62 +9,18 @@ #pragma once -#include "react/detail/Defs.h" -#include "react/API.h" -#include "react/Group.h" +#include "react/detail/defs.h" +#include "react/api.h" +#include "react/group.h" +#include "react/common/ptrcache.h" #include #include #include -#include "react/detail/graph/EventNodes.h" +#include "react/detail/event_nodes.h" -/***************************************/ REACT_IMPL_BEGIN /**************************************/ - -template -class EventInternals -{ -protected: - using NodeType = EventStreamNode; - using StorageType = typename NodeType::StorageType; - -public: - EventInternals(const EventInternals&) = default; - EventInternals& operator=(const EventInternals&) = default; - - EventInternals(EventInternals&&) = default; - EventInternals& operator=(EventInternals&&) = default; - - EventInternals(std::shared_ptr&& nodePtr) : - nodePtr_( std::move(nodePtr) ) - { } - - auto GetNodePtr() -> std::shared_ptr& - { return nodePtr_; } - - auto GetNodePtr() const -> const std::shared_ptr& - { return nodePtr_; } - - NodeId GetNodeId() const - { return nodePtr_->GetNodeId(); } - StorageType& Events() - { return nodePtr_->Events(); } - - const StorageType& Events() const - { return nodePtr_->Events(); } - - void SetPendingSuccessorCount(size_t count) - { nodePtr_->SetPendingSuccessorCount(count); } - - void DecrementPendingSuccessorCount() - { nodePtr_->DecrementPendingSuccessorCount(); } - -private: - std::shared_ptr nodePtr_; -}; - -/****************************************/ REACT_IMPL_END /***************************************/ /*****************************************/ REACT_BEGIN /*****************************************/ @@ -81,41 +37,33 @@ class Event : protected REACT_IMPL::EventInternals Event(Event&&) = default; Event& operator=(Event&&) = default; + // Construct with explicit group template - Event(F&& func, const Event& dep) : - Event::Event( REACT_IMPL::CtorTag{ }, CreateProcessingNode(dep.GetGroup(), std::forward(func), dep) ) - { } + Event(const Group& group, F&& func, const Event& dep) : + Event::Event( CreateProcessingNode(group, std::forward(func), dep) ) + { } + // Construct with implicit group template - Event(const Group& group, F&& func, const Event& dep) : - Event::Event( REACT_IMPL::CtorTag{ }, CreateProcessingNode(group, std::forward(func), dep) ) - { } + Event(F&& func, const Event& dep) : + Event::Event( CreateProcessingNode(dep.GetGroup(), std::forward(func), dep) ) + { } + // Construct with explicit group template - Event(F&& func, const Event& dep, const Signal& ... signals) : - Event::Event( REACT_IMPL::CtorTag{ }, CreateSyncedProcessingNode(dep.GetGroup(), std::forward(func), dep, signals ...) ) - { } + Event(const Group& group, F&& func, const Event& dep, const Signal& ... signals) : + Event::Event( CreateSyncedProcessingNode(group, std::forward(func), dep, signals ...) ) + { } + // Construct with implicit group template - Event(const Group& group, F&& func, const Event& dep, const Signal& ... signals) : - Event::Event( REACT_IMPL::CtorTag{ }, CreateSyncedProcessingNode(group, std::forward(func), dep, signals ...) ) - { } + Event(F&& func, const Event& dep, const Signal& ... signals) : + Event::Event( CreateSyncedProcessingNode(dep.GetGroup(), std::forward(func), dep, signals ...) ) + { } auto Tokenize() const -> decltype(auto) { return REACT::Tokenize(*this); } - /*template - auto Merge(Us&& ... deps) const -> decltype(auto) - { return REACT::Merge(*this, std::forward(deps) ...); } - - template - auto Filter(F&& pred) const -> decltype(auto) - { return REACT::Filter(std::forward(pred), *this); } - - template - auto Transform(F&& pred) const -> decltype(auto) - { return REACT::Transform(*this, std::forward(f)); }*/ - auto GetGroup() const -> const Group& { return GetNodePtr()->GetGroup(); } @@ -134,18 +82,11 @@ class Event : protected REACT_IMPL::EventInternals friend auto GetInternals(const Event& e) -> const REACT_IMPL::EventInternals& { return e; } -public: // Internal - template - static Event CreateWithNode(TArgs&& ... args) - { - return Event( REACT_IMPL::CtorTag{ }, std::make_shared(std::forward(args) ...) ); - } - protected: // Private node ctor - Event(REACT_IMPL::CtorTag, std::shared_ptr>&& nodePtr) : + explicit Event(std::shared_ptr>&& nodePtr) : Event::EventInternals( std::move(nodePtr) ) - { } + { } template auto CreateProcessingNode(const Group& group, F&& func, const Event& dep) -> decltype(auto) @@ -166,6 +107,9 @@ class Event : protected REACT_IMPL::EventInternals return std::make_shared::type, Us ...>>( group, std::forward(func), SameGroupOrLink(group, dep), SameGroupOrLink(group, syncs) ...); } + + template + friend static RET impl::CreateWrappedNode(ARGS&& ... args); }; /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -183,8 +127,8 @@ class EventSource : public Event // Construct event source explicit EventSource(const Group& group) : - EventSource::Event( REACT_IMPL::CtorTag{ }, CreateSourceNode(group) ) - { } + EventSource::Event( CreateSourceNode(group) ) + { } void Emit(const E& value) { EmitValue(value); } @@ -192,7 +136,7 @@ class EventSource : public Event void Emit(E&& value) { EmitValue(std::move(value)); } - template ::value>::type> + template >::type> void Emit() { EmitValue(Token::value); } @@ -214,10 +158,10 @@ class EventSource : public Event void EmitValue(T&& value) { using REACT_IMPL::NodeId; - using REACT_IMPL::ReactiveGraph; - using SrcNodeType = REACT_IMPL::EventSourceNode; + using REACT_IMPL::ReactGraph; + using REACT_IMPL::EventSourceNode; - SrcNodeType* castedPtr = static_cast(this->GetNodePtr().get()); + auto* castedPtr = static_cast*>(this->GetNodePtr().get()); NodeId nodeId = castedPtr->GetNodeId(); auto& graphPtr = GetInternals(this->GetGroup()).GetGraphPtr(); @@ -241,8 +185,8 @@ class EventSlot : public Event // Construct emtpy slot EventSlot(const Group& group) : - EventSlot::Event( REACT_IMPL::CtorTag{ }, CreateSlotNode(group) ) - { } + EventSlot::Event( CreateSlotNode(group) ) + { } void Add(const Event& input) { AddInput(input); } @@ -316,50 +260,41 @@ class EventLink : public Event // Construct with group EventLink(const Group& group, const Event& input) : - EventLink::Event( REACT_IMPL::CtorTag{ }, GetOrCreateLinkNode(group, input) ) - { } + EventLink::Event( GetOrCreateLinkNode(group, input) ) + { } protected: static auto GetOrCreateLinkNode(const Group& group, const Event& input) -> decltype(auto) { using REACT_IMPL::EventLinkNode; - - auto& targetGraphPtr = GetInternals(group).GetGraphPtr(); - auto& linkCache = targetGraphPtr->GetLinkCache(); + using REACT_IMPL::IReactNode; + using REACT_IMPL::ReactGraph; - void* k1 = GetInternals(input.GetGroup()).GetGraphPtr().get(); - void* k2 = GetInternals(input).GetNodePtr().get(); + IReactNode* k = GetInternals(input).GetNodePtr().get(); + + ReactGraph::LinkCache& linkCache = GetInternals(group).GetGraphPtr()->GetLinkCache(); - auto nodePtr = linkCache.LookupOrCreate>( - { k1, k2 }, + std::shared_ptr nodePtr = linkCache.LookupOrCreate( + k, [&] { auto nodePtr = std::make_shared>(group, input); nodePtr->SetWeakSelfPtr(std::weak_ptr>{ nodePtr }); - return nodePtr; + return std::static_pointer_cast(nodePtr); }); - return nodePtr; + return std::static_pointer_cast>(nodePtr); } }; /////////////////////////////////////////////////////////////////////////////////////////////////// /// Merge /////////////////////////////////////////////////////////////////////////////////////////////////// -template -auto Merge(const Group& group, const Event& dep1, const Event& ... deps) -> decltype(auto) +template +auto Merge(const Group& group, const Event& dep1, const Event& ... deps) -> decltype(auto) { using REACT_IMPL::EventMergeNode; using REACT_IMPL::SameGroupOrLink; - using REACT_IMPL::CtorTag; - - static_assert(sizeof...(Us) > 0, "Merge requires at least 2 inputs."); - - // If supplied, use merge type, otherwise default to common type. - using E = typename std::conditional< - std::is_same::value, - typename std::common_type::type, - T>::type; return Event::CreateWithNode>(group, SameGroupOrLink(group, dep1), SameGroupOrLink(group, deps) ...); } @@ -433,17 +368,6 @@ template auto Transform(F&& op, const Event& dep, const Signal& ... signals) -> Event { return Transform(dep.GetGroup(), std::forward(op), dep, signals ...); } -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Flatten -/////////////////////////////////////////////////////////////////////////////////////////////////// -/*template -auto Flatten(const Signal>& outer) -> Events -{ - return Events( - std::make_shared, TInnerValue>>( - GetNodePtr(outer), GetNodePtr(outer.Value()))); -}*/ - /////////////////////////////////////////////////////////////////////////////////////////////////// /// Join /////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/include/react/Group.h b/include/react/Group.h index dd62b012..45ec476a 100644 --- a/include/react/Group.h +++ b/include/react/Group.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2016. +// Copyright Sebastian Jeckel 2017. // 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) @@ -9,15 +9,16 @@ #pragma once -#include "react/detail/Defs.h" +#include "react/detail/defs.h" #include #include #include "react/API.h" +#include "react/common/syncpoint.h" -#include "react/detail/IReactiveGraph.h" -#include "react/detail/graph/PropagationST.h" +#include "react/detail/graph_interface.h" +#include "react/detail/graph_impl.h" /***************************************/ REACT_IMPL_BEGIN /**************************************/ @@ -26,7 +27,7 @@ /////////////////////////////////////////////////////////////////////////////////////////////////// class GroupInternals { - using GraphType = REACT_IMPL::ReactiveGraph; + using GraphType = REACT_IMPL::ReactGraph; public: GroupInternals() : @@ -53,62 +54,6 @@ class GroupInternals /*****************************************/ REACT_BEGIN /*****************************************/ -#if 0 - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// TransactionStatus -/////////////////////////////////////////////////////////////////////////////////////////////////// -class TransactionStatus -{ - using StateT = REACT_IMPL::SharedWaitingState; - using PtrT = REACT_IMPL::WaitingStatePtrT; - -public: - // Default ctor - TransactionStatus() : - statePtr_( StateT::Create() ) - { } - - // Move ctor - TransactionStatus(TransactionStatus&& other) : - statePtr_( std::move(other.statePtr_) ) - { - other.statePtr_ = StateT::Create(); - } - - // Move assignment - TransactionStatus& operator=(TransactionStatus&& other) - { - if (this != &other) - { - statePtr_ = std::move(other.statePtr_); - other.statePtr_ = StateT::Create(); - } - return *this; - } - - // Deleted copy ctor & assignment - TransactionStatus(const TransactionStatus&) = delete; - TransactionStatus& operator=(const TransactionStatus&) = delete; - - void Wait() - { - assert(statePtr_.Get() != nullptr); - statePtr_->Wait(); - } - -private: - PtrT statePtr_; - - template - friend void AsyncTransaction(TransactionStatus& status, F&& func); - - template - friend void AsyncTransaction(TransactionFlagsT flags, TransactionStatus& status, F&& func); -}; - -#endif - /////////////////////////////////////////////////////////////////////////////////////////////////// /// Group /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -128,12 +73,12 @@ class Group : protected REACT_IMPL::GroupInternals { GetGraphPtr()->DoTransaction(std::forward(func)); } template - void EnqueueTransaction(F&& func) - { EnqueueTransaction(TransactionFlags::none, std::forward(func)); } + void EnqueueTransaction(F&& func, TransactionFlags flags = TransactionFlags::none) + { GetGraphPtr()->EnqueueTransaction(std::forward(func), SyncPoint::Dependency{ }, flags); } template - void EnqueueTransaction(TransactionFlags flags, F&& func) - { GetGraphPtr()->EnqueueTransaction(flags, std::forward(func)); } + void EnqueueTransaction(F&& func, const SyncPoint& syncPoint, TransactionFlags flags = TransactionFlags::none) + { GetGraphPtr()->EnqueueTransaction(std::forward(func), SyncPoint::Dependency{ syncPoint }, flags); } friend bool operator==(const Group& a, const Group& b) { return a.GetGraphPtr() == b.GetGraphPtr(); } diff --git a/include/react/Observer.h b/include/react/Observer.h index a2ff497a..1f28136d 100644 --- a/include/react/Observer.h +++ b/include/react/Observer.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2016. +// Copyright Sebastian Jeckel 2017. // 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) @@ -9,21 +9,54 @@ #pragma once -#include "react/detail/Defs.h" -#include "react/API.h" -#include "react/Group.h" +#include "react/detail/defs.h" +#include "react/api.h" +#include "react/group.h" #include #include -#include "react/detail/graph/ObserverNodes.h" +#include "react/detail/observer_nodes.h" + +/***************************************/ REACT_IMPL_BEGIN /**************************************/ + +class ObserverInternals +{ +public: + ObserverInternals(const ObserverInternals&) = default; + ObserverInternals& operator=(const ObserverInternals&) = default; + + ObserverInternals(ObserverInternals&&) = default; + ObserverInternals& operator=(ObserverInternals&&) = default; + + explicit ObserverInternals(std::shared_ptr&& nodePtr) : + nodePtr_( std::move(nodePtr) ) + { } + + auto GetNodePtr() -> std::shared_ptr& + { return nodePtr_; } + + auto GetNodePtr() const -> const std::shared_ptr& + { return nodePtr_; } + + NodeId GetNodeId() const + { return nodePtr_->GetNodeId(); } + +protected: + ObserverInternals() = default; + +private: + std::shared_ptr nodePtr_; +}; + +/****************************************/ REACT_IMPL_END /***************************************/ /*****************************************/ REACT_BEGIN /*****************************************/ /////////////////////////////////////////////////////////////////////////////////////////////////// /// ObserverBase /////////////////////////////////////////////////////////////////////////////////////////////////// -class Observer +class Observer : protected REACT_IMPL::ObserverInternals { private: using NodeType = REACT_IMPL::ObserverNode; @@ -38,50 +71,44 @@ class Observer // Construct signal observer with explicit group template Observer(const Group& group, F&& func, const Signal& subject1, const Signal& ... subjects) : - Observer::Observer(REACT_IMPL::CtorTag{ }, CreateSignalObserverNode(group, std::forward(func), subject1, subjects ...)) - { } + Observer::Observer( CreateSignalObserverNode(group, std::forward(func), subject1, subjects ...)) + { } // Construct signal observer with implicit group template Observer(F&& func, const Signal& subject1, const Signal& ... subjects) : - Observer::Observer(REACT_IMPL::CtorTag{ }, CreateSignalObserverNode(subject1.GetGroup(), std::forward(func), subject1, subjects ...)) - { } + Observer::Observer( CreateSignalObserverNode(subject1.GetGroup(), std::forward(func), subject1, subjects ...)) + { } // Construct event observer with explicit group template Observer(const Group& group, F&& func, const Event& subject) : - Observer::Observer(REACT_IMPL::CtorTag{ }, CreateEventObserverNode(group, std::forward(func), subject)) - { } + Observer::Observer( CreateEventObserverNode(group, std::forward(func), subject)) + { } // Construct event observer with implicit group template Observer(F&& func, const Event& subject) : - Observer::Observer(REACT_IMPL::CtorTag{ }, CreateEventObserverNode(subject.GetGroup(), std::forward(func), subject)) - { } + Observer::Observer( CreateEventObserverNode(subject.GetGroup(), std::forward(func), subject)) + { } // Constructed synced event observer with explicit group template Observer(const Group& group, F&& func, const Event& subject, const Signal& ... signals) : - Observer::Observer(REACT_IMPL::CtorTag{ }, CreateSyncedEventObserverNode(group, std::forward(func), subject, signals ...)) - { } + Observer::Observer( CreateSyncedEventObserverNode(group, std::forward(func), subject, signals ...)) + { } // Constructed synced event observer with implicit group template Observer(F&& func, const Event& subject, const Signal& ... signals) : - Observer::Observer(REACT_IMPL::CtorTag{ }, CreateSyncedEventObserverNode(subject.GetGroup(), std::forward(func), subject, signals ...)) - { } + Observer::Observer( CreateSyncedEventObserverNode(subject.GetGroup(), std::forward(func), subject, signals ...)) + { } public: //Internal // Private node ctor - Observer(REACT_IMPL::CtorTag, std::shared_ptr&& nodePtr) : + explicit Observer(std::shared_ptr&& nodePtr) : nodePtr_(std::move(nodePtr)) - { } - - auto NodePtr() -> std::shared_ptr& - { return nodePtr_; } - - auto NodePtr() const -> const std::shared_ptr& - { return nodePtr_; } + { } protected: template diff --git a/include/react/Signal.h b/include/react/Signal.h index a429f34b..c7e11e8f 100644 --- a/include/react/Signal.h +++ b/include/react/Signal.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2016. +// Copyright Sebastian Jeckel 2017. // 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) @@ -9,53 +9,18 @@ #pragma once -#include "react/detail/Defs.h" -#include "react/API.h" -#include "react/Group.h" +#include "react/detail/defs.h" +#include "react/api.h" +#include "react/group.h" +#include "react/common/ptrcache.h" #include #include #include #include -#include "react/detail/graph/SignalNodes.h" +#include "react/detail/signal_nodes.h" -/***************************************/ REACT_IMPL_BEGIN /**************************************/ - -template -class SignalInternals -{ -public: - SignalInternals(const SignalInternals&) = default; - SignalInternals& operator=(const SignalInternals&) = default; - - SignalInternals(SignalInternals&&) = default; - SignalInternals& operator=(SignalInternals&&) = default; - - SignalInternals(std::shared_ptr>&& nodePtr) : - nodePtr_( std::move(nodePtr) ) - { } - - auto GetNodePtr() -> std::shared_ptr>& - { return nodePtr_; } - - auto GetNodePtr() const -> const std::shared_ptr>& - { return nodePtr_; } - - NodeId GetNodeId() const - { return nodePtr_->GetNodeId(); } - - S& Value() - { return nodePtr_->Value(); } - - const S& Value() const - { return nodePtr_->Value(); } - -private: - std::shared_ptr> nodePtr_; -}; - -/****************************************/ REACT_IMPL_END /***************************************/ /*****************************************/ REACT_BEGIN /*****************************************/ @@ -76,13 +41,13 @@ class Signal : protected REACT_IMPL::SignalInternals template explicit Signal(const Group& group, F&& func, const Signal& dep1, const Signal& ... deps) : Signal::SignalInternals( CreateFuncNode(group, std::forward(func), dep1, deps ...) ) - { } + { } // Construct with implicit group template explicit Signal(F&& func, const Signal& dep1, const Signal& ... deps) : Signal::SignalInternals( CreateFuncNode(dep1.GetGroup(), std::forward(func), dep1, deps ...) ) - { } + { } auto GetGroup() const -> const Group& { return this->GetNodePtr()->GetGroup(); } @@ -102,23 +67,24 @@ class Signal : protected REACT_IMPL::SignalInternals friend auto GetInternals(const Signal& s) -> const REACT_IMPL::SignalInternals& { return s; } - template - static Signal CreateWithNode(TArgs&& ... args) - { return Signal( REACT_IMPL::CtorTag{ }, std::make_shared(std::forward(args) ...) ); } - protected: - Signal(REACT_IMPL::CtorTag, std::shared_ptr>&& nodePtr) : + explicit Signal(std::shared_ptr>&& nodePtr) : Signal::SignalInternals( std::move(nodePtr) ) - { } + { } +private: template auto CreateFuncNode(const Group& group, F&& func, const Signal& dep1, const Signal& ... deps) -> decltype(auto) { using REACT_IMPL::SignalFuncNode; + using REACT_IMPL::SameGroupOrLink; return std::make_shared::type, T1, Ts ...>>( group, std::forward(func), SameGroupOrLink(group, dep1), SameGroupOrLink(group, deps) ...); } + + template + friend RET impl::CreateWrappedNode(ARGS&& ... args); }; /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -136,14 +102,14 @@ class VarSignal : public Signal // Construct with group + default explicit VarSignal(const Group& group) : - VarSignal::Signal( REACT_IMPL::CtorTag{ }, CreateVarNode(group) ) - { } + VarSignal::Signal( CreateVarNode(group) ) + { } // Construct with group + value template VarSignal(const Group& group, T&& value) : - VarSignal::Signal( REACT_IMPL::CtorTag{ }, CreateVarNode(group, std::forward(value)) ) - { } + VarSignal::Signal( CreateVarNode(group, std::forward(value)) ) + { } void Set(const S& newValue) { SetValue(newValue); } @@ -151,12 +117,6 @@ class VarSignal : public Signal void Set(S&& newValue) { SetValue(std::move(newValue)); } - void operator<<=(const S& newValue) - { SetValue(newValue); } - - void operator<<=(S&& newValue) - { SetValue(std::move(newValue)); } - template void Modify(const F& func) { ModifyValue(func); } @@ -168,6 +128,11 @@ class VarSignal : public Signal { return !(a == b); } protected: + explicit VarSignal(std::shared_ptr>&& nodePtr) : + VarSignal::Signal( std::move(nodePtr) ) + { } + +private: static auto CreateVarNode(const Group& group) -> decltype(auto) { using REACT_IMPL::VarSignalNode; @@ -181,7 +146,6 @@ class VarSignal : public Signal return std::make_shared>(group, std::forward(value)); } -private: template void SetValue(T&& newValue) { @@ -226,13 +190,13 @@ class SignalSlot : public Signal // Construct with explicit group SignalSlot(const Group& group, const Signal& input) : - SignalSlot::Signal( REACT_IMPL::CtorTag{ }, CreateSlotNode(group, input) ) - { } + SignalSlot::Signal( CreateSlotNode(group, input) ) + { } // Construct with implicit group explicit SignalSlot(const Signal& input) : - SignalSlot::Signal( REACT_IMPL::CtorTag{ }, CreateSlotNode(input.GetGroup(), input) ) - { } + SignalSlot::Signal( CreateSlotNode(input.GetGroup(), input) ) + { } void Set(const Signal& newInput) { SetInput(newInput); } @@ -241,19 +205,26 @@ class SignalSlot : public Signal { SetInput(newInput); } protected: + explicit SignalSlot(std::shared_ptr>&& nodePtr) : + SignalSlot::Signal( std::move(nodePtr) ) + { } + +private: static auto CreateSlotNode(const Group& group, const Signal& input) -> decltype(auto) { using REACT_IMPL::SignalSlotNode; + using REACT_IMPL::SameGroupOrLink; + return std::make_shared>(group, SameGroupOrLink(group, input)); } -private: void SetInput(const Signal& newInput) { using REACT_IMPL::NodeId; - using SlotNodeType = REACT_IMPL::SignalSlotNode; + using REACT_IMPL::SignalSlotNode; + using REACT_IMPL::SameGroupOrLink; - SlotNodeType* castedPtr = static_cast(this->GetNodePtr().get()); + auto* castedPtr = static_cast*>(this->GetNodePtr().get()); NodeId nodeId = castedPtr->GetInputNodeId(); auto& graphPtr = GetInternals(this->GetGroup()).GetGraphPtr(); @@ -277,31 +248,30 @@ class SignalLink : public Signal // Construct with group SignalLink(const Group& group, const Signal& input) : - SignalLink::Signal( REACT_IMPL::CtorTag{ }, GetOrCreateLinkNode(group, input) ) - { } + SignalLink::Signal( GetOrCreateLinkNode(group, input) ) + { } protected: static auto GetOrCreateLinkNode(const Group& group, const Signal& input) -> decltype(auto) { using REACT_IMPL::SignalLinkNode; - - auto targetGraphPtr = GetInternals(group).GetGraphPtr(); + using REACT_IMPL::IReactNode; + using REACT_IMPL::ReactGraph; - void* k1 = GetInternals(input.GetGroup()).GetGraphPtr().get(); - void* k2 = GetInternals(input).GetNodePtr().get(); + IReactNode* k = GetInternals(input).GetNodePtr().get(); - auto& linkCache = targetGraphPtr->GetLinkCache(); + ReactGraph::LinkCache& linkCache = GetInternals(group).GetGraphPtr()->GetLinkCache(); - auto nodePtr = linkCache.LookupOrCreate>( - { k1, k2 }, + std::shared_ptr nodePtr = linkCache.LookupOrCreate( + k, [&] { auto nodePtr = std::make_shared>(group, input); nodePtr->SetWeakSelfPtr(std::weak_ptr>{ nodePtr }); - return nodePtr; + return std::static_pointer_cast(nodePtr); }); - return nodePtr; + return std::static_pointer_cast>(nodePtr); } }; diff --git a/include/react/common/Concurrency.h b/include/react/common/Concurrency.h deleted file mode 100644 index 0a5c350c..00000000 --- a/include/react/common/Concurrency.h +++ /dev/null @@ -1,324 +0,0 @@ - -// Copyright Sebastian Jeckel 2016. -// 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) - -#ifndef REACT_COMMON_CONCURRENCY_H_INCLUDED -#define REACT_COMMON_CONCURRENCY_H_INCLUDED - -#pragma once - -#include "react/detail/Defs.h" - -#include -#include - -#include "react/common/RefCounting.h" - -/***************************************/ REACT_IMPL_BEGIN /**************************************/ - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// IWaitingState -/////////////////////////////////////////////////////////////////////////////////////////////////// -class IWaitingState -{ -public: - virtual inline ~IWaitingState() {} - - virtual void Wait() = 0; - - virtual void IncWaitCount() = 0; - virtual void DecWaitCount() = 0; - -protected: - virtual bool IsRefCounted() const = 0; - virtual void IncRefCount() = 0; - virtual void DecRefCount() = 0; - - friend class IntrusiveRefCountingPtr; -}; - -using WaitingStatePtrT = IntrusiveRefCountingPtr; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// WaitingStateBase -/////////////////////////////////////////////////////////////////////////////////////////////////// -class WaitingStateBase : public IWaitingState -{ -public: - virtual inline void Wait() override - { - std::unique_lock lock(mutex_); - condition_.wait(lock, [this] { return !isWaiting_; }); - } - - virtual inline void IncWaitCount() override - { - auto oldVal = waitCount_.fetch_add(1, std::memory_order_relaxed); - - if (oldVal == 0) - {// mutex_ - std::lock_guard scopedLock(mutex_); - isWaiting_ = true; - }// ~mutex_ - } - - virtual inline void DecWaitCount() override - { - auto oldVal = waitCount_.fetch_sub(1, std::memory_order_relaxed); - - if (oldVal == 1) - {// mutex_ - std::lock_guard scopedLock(mutex_); - isWaiting_ = false; - condition_.notify_all(); - }// ~mutex_ - } - - inline bool IsWaiting() - {// mutex_ - std::lock_guard scopedLock(mutex_); - return isWaiting_; - }// ~mutex_ - - template - auto Run(F&& func) -> decltype(func(false)) - {// mutex_ - std::lock_guard scopedLock(mutex_); - return func(isWaiting_); - }// ~mutex_ - - template - bool RunIfWaiting(F&& func) - {// mutex_ - std::lock_guard scopedLock(mutex_); - - if (!isWaiting_) - return false; - - func(); - return true; - }// ~mutex_ - - template - bool RunIfNotWaiting(F&& func) - {// mutex_ - std::lock_guard scopedLock(mutex_); - - if (isWaiting_) - return false; - - func(); - return true; - }// ~mutex_ - -private: - std::atomic waitCount_{ 0 }; - std::condition_variable condition_; - std::mutex mutex_; - bool isWaiting_ = false; -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// UniqueWaitingState -/////////////////////////////////////////////////////////////////////////////////////////////////// -class UniqueWaitingState : public WaitingStateBase -{ -protected: - // Do nothing - virtual inline bool IsRefCounted() const override { return false; } - virtual inline void IncRefCount() override {} - virtual inline void DecRefCount() override {} -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// SharedWaitingState -/////////////////////////////////////////////////////////////////////////////////////////////////// -class SharedWaitingState : public WaitingStateBase -{ -private: - SharedWaitingState() = default; - -public: - static inline WaitingStatePtrT Create() - { - return WaitingStatePtrT(new SharedWaitingState()); - } - - -protected: - virtual inline bool IsRefCounted() const override { return true; } - - virtual inline void IncRefCount() override - { - refCount_.fetch_add(1, std::memory_order_relaxed); - } - - virtual inline void DecRefCount() override - { - auto oldVal = refCount_.fetch_sub(1, std::memory_order_relaxed); - - if (oldVal == 1) - delete this; - } - -private: - std::atomic refCount_{ 0 }; -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// SharedWaitingStateCollection -/////////////////////////////////////////////////////////////////////////////////////////////////// -class SharedWaitingStateCollection : public IWaitingState -{ -private: - SharedWaitingStateCollection(std::vector&& others) : - others_( std::move(others) ) - {} - -public: - static inline WaitingStatePtrT Create(std::vector&& others) - { - return WaitingStatePtrT(new SharedWaitingStateCollection(std::move(others))); - } - - virtual inline bool IsRefCounted() const override { return true; } - - virtual inline void Wait() override - { - for (const auto& e : others_) - e->Wait(); - } - - virtual inline void IncWaitCount() override - { - for (const auto& e : others_) - e->IncWaitCount(); - } - - virtual inline void DecWaitCount() override - { - for (const auto& e : others_) - e->DecWaitCount(); - } - - virtual inline void IncRefCount() override - { - refCount_.fetch_add(1, std::memory_order_relaxed); - } - - virtual inline void DecRefCount() override - { - auto oldVal = refCount_.fetch_sub(1, std::memory_order_relaxed); - - if (oldVal == 1) - delete this; - } - -private: - std::atomic refCount_{ 0 }; - std::vector others_; -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// BlockingCondition -/////////////////////////////////////////////////////////////////////////////////////////////////// -class BlockingCondition -{ -public: - inline void Block() - {// mutex_ - std::lock_guard scopedLock(mutex_); - blocked_ = true; - }// ~mutex_ - - inline void Unblock() - {// mutex_ - std::lock_guard scopedLock(mutex_); - blocked_ = false; - condition_.notify_all(); - }// ~mutex_ - - inline void WaitForUnblock() - { - std::unique_lock lock(mutex_); - condition_.wait(lock, [this] { return !blocked_; }); - } - - inline bool IsBlocked() - {// mutex_ - std::lock_guard scopedLock(mutex_); - return blocked_; - }// ~mutex_ - - template - auto Run(F&& func) -> decltype(func(false)) - {// mutex_ - std::lock_guard scopedLock(mutex_); - return func(blocked_); - }// ~mutex_ - - template - bool RunIfBlocked(F&& func) - {// mutex_ - std::lock_guard scopedLock(mutex_); - - if (!blocked_) - return false; - - func(); - return true; - }// ~mutex_ - - template - bool RunIfUnblocked(F&& func) - {// mutex_ - std::lock_guard scopedLock(mutex_); - - if (blocked_) - return false; - - func(); - return true; - }// ~mutex_ - -private: - std::mutex mutex_; - std::condition_variable condition_; - - bool blocked_ = false; -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// ConditionalCriticalSection -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -class ConditionalCriticalSection; - -template -class ConditionalCriticalSection -{ -public: - template - void Access(const F& f) { f(); } -}; - -template -class ConditionalCriticalSection -{ -public: - template - void Access(const F& f) - {// mutex_ - std::lock_guard lock(mutex_); - - f(); - }// ~mutex_ -private: - TMutex mutex_; -}; - -/****************************************/ REACT_IMPL_END /***************************************/ - -#endif // REACT_COMMON_CONCURRENCY_H_INCLUDED \ No newline at end of file diff --git a/include/react/common/RefCounting.h b/include/react/common/RefCounting.h index f2cd518a..37bb5e68 100644 --- a/include/react/common/RefCounting.h +++ b/include/react/common/RefCounting.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2016. +// Copyright Sebastian Jeckel 2017. // 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) @@ -9,7 +9,7 @@ #pragma once -#include "react/detail/Defs.h" +#include "react/detail/defs.h" #include #include diff --git a/include/react/common/SourceIdSet.h b/include/react/common/SourceIdSet.h index b1a3eeb0..902a39aa 100644 --- a/include/react/common/SourceIdSet.h +++ b/include/react/common/SourceIdSet.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2016. +// Copyright Sebastian Jeckel 2017. // 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) @@ -9,7 +9,7 @@ #pragma once -#include "react/detail/Defs.h" +#include "react/detail/defs.h" #include #include diff --git a/include/react/common/Timing.h b/include/react/common/Timing.h index 84c58006..7d6c81ac 100644 --- a/include/react/common/Timing.h +++ b/include/react/common/Timing.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2016. +// Copyright Sebastian Jeckel 2017. // 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) @@ -9,7 +9,7 @@ #pragma once -#include "react/detail/Defs.h" +#include "react/detail/defs.h" #include diff --git a/include/react/common/TopoQueue.h b/include/react/common/TopoQueue.h index 091d116f..2c3c4613 100644 --- a/include/react/common/TopoQueue.h +++ b/include/react/common/TopoQueue.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2016. +// Copyright Sebastian Jeckel 2017. // 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) @@ -9,7 +9,7 @@ #pragma once -#include "react/detail/Defs.h" +#include "react/detail/defs.h" #include #include diff --git a/include/react/common/Types.h b/include/react/common/Types.h index 0545f858..30a377fa 100644 --- a/include/react/common/Types.h +++ b/include/react/common/Types.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2016. +// Copyright Sebastian Jeckel 2017. // 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) @@ -9,7 +9,7 @@ #pragma once -#include "react/detail/Defs.h" +#include "react/detail/defs.h" #include #include diff --git a/include/react/common/Util.h b/include/react/common/Util.h deleted file mode 100644 index 4721723d..00000000 --- a/include/react/common/Util.h +++ /dev/null @@ -1,249 +0,0 @@ - -// Copyright Sebastian Jeckel 2016. -// 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) - -#ifndef REACT_COMMON_UTIL_H_INCLUDED -#define REACT_COMMON_UTIL_H_INCLUDED - -#pragma once - -#include "react/detail/Defs.h" - -#include -#include -#include - -/***************************************/ REACT_IMPL_BEGIN /**************************************/ - -template -struct MakeVoid { using type = void;}; - -template -using VoidType = typename MakeVoid::type; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Unpack tuple - see -/// http://stackoverflow.com/questions/687490/how-do-i-expand-a-tuple-into-variadic-template-functions-arguments -/////////////////////////////////////////////////////////////////////////////////////////////////// - -template -struct Apply { - template - static auto apply(F&& f, T&& t, A&&... a) -> decltype(auto) - { - return Apply::apply(std::forward(f), std::forward(t), std::get(std::forward(t)), std::forward(a)...); - } -}; - -template<> -struct Apply<0> -{ - template - static auto apply(F&& f, T&&, A&&... a) -> decltype(auto) - { - return std::forward(f)(std::forward(a)...); - } -}; - -template -inline auto apply(F&& f, T&& t) -> decltype(auto) -{ - return Apply::type>::value>::apply(std::forward(f), std::forward(t)); -} - -template -struct ApplyMemberFn { - template - static inline auto apply(O obj, F f, T && t, A &&... a) -> decltype(auto) - { - return ApplyMemberFn::apply(obj, f, std::forward(t), std::get(std::forward(t)), std::forward(a)...); - } -}; - -template<> -struct ApplyMemberFn<0> -{ - template - static inline auto apply(O obj, F f, T &&, A &&... a) - -> decltype((obj->*f)(std::forward(a)...)) - { - return (obj->*f)(std::forward(a)...); - } -}; - -template -inline auto applyMemberFn(O obj, F f, T&& t) - -> decltype(ApplyMemberFn::type>::value>::apply(obj, f, std::forward(t))) -{ - return ApplyMemberFn::type>::value> - ::apply(obj, f, std::forward(t)); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Helper to enable calling a function on each element of an argument pack. -/// We can't do f(args) ...; because ... expands with a comma. -/// But we can do nop_func(f(args) ...); -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -inline void pass(TArgs&& ...) {} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// Identity (workaround to enable enable decltype()::X) -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -struct Identity -{ - using Type = T; -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// DontMove! -/////////////////////////////////////////////////////////////////////////////////////////////////// -struct DontMove {}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// DisableIfSame -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -struct DisableIfSame : - std::enable_if::type, - typename std::decay::type>::value> {}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// AddDummyArgWrapper -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -struct AddDummyArgWrapper -{ - AddDummyArgWrapper(const AddDummyArgWrapper& other) = default; - - AddDummyArgWrapper(AddDummyArgWrapper&& other) : - MyFunc( std::move(other.MyFunc) ) - {} - - template ::type> - explicit AddDummyArgWrapper(FIn&& func) : MyFunc( std::forward(func) ) {} - - TRet operator()(TArg, TDepValues& ... args) - { - return MyFunc(args ...); - } - - F MyFunc; -}; - -template -struct AddDummyArgWrapper -{ -public: - AddDummyArgWrapper(const AddDummyArgWrapper& other) = default; - - AddDummyArgWrapper(AddDummyArgWrapper&& other) : - MyFunc( std::move(other.MyFunc) ) - {} - - template ::type> - explicit AddDummyArgWrapper(FIn&& func) : MyFunc( std::forward(func) ) {} - - void operator()(TArg, TDepValues& ... args) - { - MyFunc(args ...); - } - - F MyFunc; -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// AddDefaultReturnValueWrapper -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename F, - typename TRet, - TRet return_value -> -struct AddDefaultReturnValueWrapper -{ - AddDefaultReturnValueWrapper(const AddDefaultReturnValueWrapper&) = default; - - AddDefaultReturnValueWrapper(AddDefaultReturnValueWrapper&& other) : - MyFunc( std::move(other.MyFunc) ) - {} - - template - < - typename FIn, - class = typename DisableIfSame::type - > - explicit AddDefaultReturnValueWrapper(FIn&& func) : - MyFunc( std::forward(func) ) - {} - - template - TRet operator()(TArgs&& ... args) - { - MyFunc(std::forward(args) ...); - return return_value; - } - - F MyFunc; -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// IsCallableWith -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -class IsCallableWith -{ -private: - using NoT = char[1]; - using YesT = char[2]; - - template - < - typename U, - typename = decltype(static_cast((std::declval())(std::declval() ...))) - > - static YesT& check(void*); - - template - static NoT& check(...); - -public: - static const bool value = sizeof(check(nullptr)) == sizeof(YesT); -}; - -template -bool IsBitmaskSet(T flags, T mask) -{ - return (flags & mask) != (T)0; -} - -/****************************************/ REACT_IMPL_END /***************************************/ - -// Expand args by wrapping them in a dummy function -// Use comma operator to replace potential void return value with 0 -#define REACT_EXPAND_PACK(...) REACT_IMPL::pass((__VA_ARGS__ , 0) ...) - -#define REACT_DEFINE_BITMASK_OPERATORS(t) \ - inline t operator|(t lhs, t rhs) \ - { return static_cast(static_cast::type>(lhs) | static_cast::type>(rhs)); } \ - inline t operator&(t lhs, t rhs) \ - { return static_cast(static_cast::type>(lhs) & static_cast::type>(rhs)); } \ - inline t operator^(t lhs, t rhs) \ - { return static_cast(static_cast::type>(lhs) ^ static_cast::type>(rhs)); } \ - inline t operator~(t rhs) \ - { return static_cast(~static_cast::type>(rhs)); } \ - inline t& operator|=(t& lhs, t rhs) \ - { lhs = static_cast(static_cast::type>(lhs) | static_cast::type>(rhs)); return lhs; } \ - inline t& operator&=(t& lhs, t rhs) \ - { lhs = static_cast(static_cast::type>(lhs) & static_cast::type>(rhs)); return lhs; } \ - inline t& operator^=(t& lhs, t rhs) \ - { lhs = static_cast(static_cast::type>(lhs) ^ static_cast::type>(rhs)); return lhs; } - -// Bitmask helper - -#endif // REACT_COMMON_UTIL_H_INCLUDED \ No newline at end of file diff --git a/include/react/common/expected.h b/include/react/common/expected.h new file mode 100644 index 00000000..5bdff539 --- /dev/null +++ b/include/react/common/expected.h @@ -0,0 +1,218 @@ + +// Copyright Sebastian Jeckel 2016. +// 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) + +#ifndef REACT_COMMON_EXPECTED_H_INCLUDED +#define REACT_COMMON_EXPECTED_H_INCLUDED + +#pragma once + +#include "react/detail/Defs.h" + +#include +#include +#include +#include + +/*****************************************/ REACT_BEGIN /*****************************************/ + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// IError +/////////////////////////////////////////////////////////////////////////////////////////////////// +class IErrorCause +{ +public: + virtual ~IErrorCause() = default; + + virtual std::string GetMessage() const = 0; + + virtual bool IsOfType(const char* typeId) const = 0; +}; + + +class AllocationError : public IErrorCause +{ +public: + static constexpr const char* type_id = "react::AllocationError"; + + virtual std::string GetMessage() const + { return "Allocation error."; } + + virtual bool IsOfType(const char* typeId) const + { return typeId == type_id; } +}; + + +class PreconditionError : public IErrorCause +{ +public: + static constexpr const char* type_id = "react::PreconditionError"; + + virtual std::string GetMessage() const + { return "Precondition error."; } + + virtual bool IsOfType(const char* typeId) const + { return typeId == type_id; } +}; + + +class PostconditionError : public IErrorCause +{ +public: + static constexpr const char* type_id = "react::PostconditionError"; + + virtual std::string GetMessage() const + { return "Postcondition error."; } + + virtual bool IsOfType(const char* typeId) const + { return typeId == type_id; } +}; + + +class MissingValueError : public IErrorCause +{ +public: + static constexpr const char* type_id = "react::MissingValueError"; + + virtual std::string GetMessage() const + { return "Missing value error."; } + + virtual bool IsOfType(const char* typeId) const + { return typeId == type_id; } +}; + + +class Error +{ +public: + template + < + typename T, + typename = std::enable_if_t> + > + Error(T cause) : + cause_(std::make_shared(std::move(cause))) + { } + + template + < + typename T, + typename = std::enable_if_t> + > + bool IsCause() const + { return cause_->IsOfType(T::type_id); } + + template + < + typename T, + typename = std::enable_if_t> + > + T* GetCause() const + { return static_cast(cause_.get()); } + + std::string GetMessage() const + { return cause_->GetMessage(); } + +private: + std::shared_ptr cause_; +}; + +static Error* GetErrorSentinel() + { return reinterpret_cast(0x1u); } + +struct ErrorDeleter +{ + void operator()(Error* p) const + { + if (p != GetErrorSentinel()) + delete p; + } +}; + +using UniqueErrorPtrType = std::unique_ptr; + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// Expected +/// +/// TODO: Optimize for different storage types to avoid branch in destructor. +/////////////////////////////////////////////////////////////////////////////////////////////////// +template +class Expected +{ +public: + Expected() = delete; + + Expected(const Expected&) = delete; + + Expected& operator=(const Expected&) = delete; + + Expected(Expected&&) = default; + + Expected& operator=(Expected&&) = default; + + Expected(const T& value) : + error_( GetErrorSentinel() ) + { + ValueRef() = value; + } + + Expected(T&& value) : + error_( GetErrorSentinel() ) + { + ValueRef() = std::move(value); + } + + Expected(Error err) : + error_(new Error(std::move(err))) + { } + + Expected(UniqueErrorPtrType&& err) : + error_(std::move(err)) + { } + + ~Expected() + { + if (error_.get() == GetErrorSentinel()) + { + Destruct(); + } + } + + explicit operator bool() const + { + return error_.get() == GetErrorSentinel(); + } + + Error GetError() + { return *error_; } + +private: + const T& ValueRef() const + { return *reinterpret_cast(&valueStorage_); } + + T& ValueRef() + { return *reinterpret_cast(&valueStorage_); } + + void Destruct() + { reinterpret_cast(&valueStorage_)->~T(); } + + std::aligned_storage_t valueStorage_; + + std::unique_ptr error_; + + template + friend typename UniqueErrorPtrType UnwindExpected(Expected&& ex); +}; + +template +typename UniqueErrorPtrType UnwindExpected(Expected&& ex) +{ + return std::move(std::move(ex).error_); +} + +/******************************************/ REACT_END /******************************************/ + +#endif // REACT_COMMON_INDEXED_STORAGE_H_INCLUDED \ No newline at end of file diff --git a/include/react/common/optional.h b/include/react/common/optional.h new file mode 100644 index 00000000..3208c33b --- /dev/null +++ b/include/react/common/optional.h @@ -0,0 +1,70 @@ + +// Copyright Sebastian Jeckel 2017. +// 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) + +#ifndef REACT_COMMON_OPTIONAL_H_INCLUDED +#define REACT_COMMON_OPTIONAL_H_INCLUDED + +#pragma once + +#include "react/detail/defs.h" + +#include +#include +#include + +struct NoValueType +{ + struct Tag {}; + + explicit constexpr NoValueType(Tag) + { } +}; + +constexpr NoValueType no_value{ NoValueType::Tag{ } }; + +/***************************************/ REACT_IMPL_BEGIN /**************************************/ + +template +class OptScalarStorage +{ +public: + OptScalarStorage() : hasValue_( false ) + { } + + OptScalarStorage(NoValueType) : hasValue_( false ) + { } + + OptScalarStorage& operator=(NoValueType) + { + hasValue_ = false; + return *this; + } + + OptScalarStorage(const OptScalarStorage&) = default; + + OptScalarStorage& operator=(const OptScalarStorage&) = default; + + bool HasValue() const + { return hasValue_; } + + const T& Value() const + { return value_; } + + T& Value() + { return value_; } + +private: + T value_; + bool hasValue_; +}; + +/****************************************/ REACT_IMPL_END /***************************************/ + +/*****************************************/ REACT_BEGIN /*****************************************/ + +/******************************************/ REACT_END /******************************************/ + +#endif // REACT_COMMON_OPTIONAL_H_INCLUDED \ No newline at end of file diff --git a/include/react/common/owned_ptr.h b/include/react/common/owned_ptr.h new file mode 100644 index 00000000..f0d06bcb --- /dev/null +++ b/include/react/common/owned_ptr.h @@ -0,0 +1,18 @@ + +// Copyright Sebastian Jeckel 2017. +// 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) + +#ifndef REACT_COMMON_OWNED_PTR_H_INCLUDED +#define REACT_COMMON_OWNED_PTR_H_INCLUDED + +#pragma once + +#include "react/detail/Defs.h" + +/*****************************************/ REACT_BEGIN /*****************************************/ + +/******************************************/ REACT_END /******************************************/ + +#endif // REACT_COMMON_OWNED_PTR_H_INCLUDED \ No newline at end of file diff --git a/include/react/common/ptrcache.h b/include/react/common/ptrcache.h new file mode 100644 index 00000000..50d71584 --- /dev/null +++ b/include/react/common/ptrcache.h @@ -0,0 +1,65 @@ + +// Copyright Sebastian Jeckel 2017. +// 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) + +#ifndef REACT_COMMON_PTR_CACHE_H_INCLUDED +#define REACT_COMMON_PTR_CACHE_H_INCLUDED + +#pragma once + +#include "react/detail/Defs.h" + +#include +#include +#include + +/*****************************************/ REACT_BEGIN /*****************************************/ + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// Stores weak pointers to V indexed by K. +/////////////////////////////////////////////////////////////////////////////////////////////////// +template +class WeakPtrCache +{ +public: + template + std::shared_ptr LookupOrCreate(const K& key, F&& createFunc) + { + std::lock_guard scopedLock(mutex_); + + auto it = map_.find(key); + if (it != map_.end()) + { + if (auto ptr = it->second.lock()) + { + return ptr; + } + } + + std::shared_ptr v = createFunc(); + auto res = map_.emplace(key, v); + return v; + } + + void Erase(const K& key) + { + std::lock_guard scopedLock(mutex_); + + auto it = map_.find(key); + if (it != map_.end()) + { + map_.erase(it); + } + } + +private: + std::mutex mutex_; + std::unordered_map> map_; +}; + + +/******************************************/ REACT_END /******************************************/ + +#endif // REACT_COMMON_INDEXED_STORAGE_H_INCLUDED \ No newline at end of file diff --git a/include/react/common/Containers.h b/include/react/common/slotmap.h similarity index 82% rename from include/react/common/Containers.h rename to include/react/common/slotmap.h index 79980acf..c0282ec0 100644 --- a/include/react/common/Containers.h +++ b/include/react/common/slotmap.h @@ -4,8 +4,8 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -#ifndef REACT_COMMON_CONTAINERS_H_INCLUDED -#define REACT_COMMON_CONTAINERS_H_INCLUDED +#ifndef REACT_COMMON_INDEXED_STORAGE_H_INCLUDED +#define REACT_COMMON_INDEXED_STORAGE_H_INCLUDED #pragma once @@ -17,13 +17,13 @@ #include #include -/***************************************/ REACT_IMPL_BEGIN /**************************************/ +/*****************************************/ REACT_BEGIN /*****************************************/ /////////////////////////////////////////////////////////////////////////////////////////////////// -/// IndexMap +/// SlotMap /////////////////////////////////////////////////////////////////////////////////////////////////// template -class IndexedStorage +class SlotMap { static const size_t initial_capacity = 8; static const size_t grow_factor = 2; @@ -33,15 +33,15 @@ class IndexedStorage public: using ValueType = T; - IndexedStorage() = default; + SlotMap() = default; - IndexedStorage(IndexedStorage&&) = default; - IndexedStorage& operator=(IndexedStorage&&) = default; + SlotMap(SlotMap&&) = default; + SlotMap& operator=(SlotMap&&) = default; - IndexedStorage(const IndexedStorage&) = delete; - IndexedStorage& operator=(const IndexedStorage&) = delete; + SlotMap(const SlotMap&) = delete; + SlotMap& operator=(const SlotMap&) = delete; - ~IndexedStorage() + ~SlotMap() { Reset(); } T& operator[](size_t index) @@ -90,26 +90,28 @@ class IndexedStorage // Skip over free indices. for (size_t j = 0; j < freeSize_; ++j) { + size_t freeIndex = freeIndices_[j]; + for (; index < totalSize; ++index) { - if (j == freeIndex_) + if (index == freeIndex) { ++index; break; } else { - data_[index].~T(); + reinterpret_cast(data_[index]).~T(); } } } // Rest for (; index < totalSize; ++index) - data_[index].~T(); + reinterpret_cast(data_[index]).~T(); size_ = 0; - freeList_ = 0; + freeSize_ = 0; } void Reset() @@ -144,7 +146,7 @@ class IndexedStorage size_t newCapacity = CalcNextCapacity(); std::unique_ptr newData{ new StorageType[newCapacity] }; - std::unique_ptr newFreeList{ new size_t[newCapacity] }; + std::unique_ptr newFreeIndices{ new size_t[newCapacity] }; // Move data to new storage for (size_t i = 0; i < capacity_; ++i) @@ -157,7 +159,7 @@ class IndexedStorage // Use new storage data_ = std::move(newData); - freeIndices_ = std::move(newFreeList); + freeIndices_ = std::move(newFreeIndices); capacity_ = newCapacity; } @@ -184,6 +186,6 @@ class IndexedStorage size_t capacity_ = 0; }; -/****************************************/ REACT_IMPL_END /***************************************/ +/******************************************/ REACT_END /******************************************/ -#endif // REACT_COMMON_CONTAINERS_H_INCLUDED \ No newline at end of file +#endif // REACT_COMMON_INDEXED_STORAGE_H_INCLUDED \ No newline at end of file diff --git a/include/react/common/syncpoint.h b/include/react/common/syncpoint.h new file mode 100644 index 00000000..7ca5586b --- /dev/null +++ b/include/react/common/syncpoint.h @@ -0,0 +1,195 @@ + +// Copyright Sebastian Jeckel 2017. +// 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) + +#ifndef REACT_COMMON_SYNCPOINT_H_INCLUDED +#define REACT_COMMON_SYNCPOINT_H_INCLUDED + +#pragma once + +#include "react/detail/defs.h" + +#include +#include +#include + + +/*****************************************/ REACT_BEGIN /*****************************************/ + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// SyncPoint +/////////////////////////////////////////////////////////////////////////////////////////////////// +class SyncPoint +{ +private: + class Dependency; + + class ISyncPointState + { + public: + virtual ~ISyncPointState() = default; + + virtual void IncrementWaitCount() = 0; + + virtual void DecrementWaitCount() = 0; + }; + + class SyncPointState : public ISyncPointState + { + public: + virtual void IncrementWaitCount() override + {// mutex_ + std::lock_guard scopedLock(mtx_); + ++waitCount_; + }// ~mutex_ + + virtual void DecrementWaitCount() override + {// mutex_ + std::lock_guard scopedLock(mtx_); + --waitCount_; + + if (waitCount_ == 0) + cv_.notify_all(); + }// ~mutex_ + + void Wait() + { + std::unique_lock lock(mtx_); + cv_.wait(lock, [this] { return waitCount_ == 0; }); + } + + template + bool WaitFor(const std::chrono::duration& relTime) + { + std::unique_lock lock(mtx_); + return cv_.wait_for(lock, relTime, [this] { return waitCount_ == 0; }); + } + + template + bool WaitUntil(const std::chrono::duration& relTime) + { + std::unique_lock lock(mtx_); + return cv_.wait_until(lock, relTime, [this] { return waitCount_ == 0; }); + } + + private: + std::mutex mtx_; + std::condition_variable cv_; + + int waitCount_ = 0; + }; + + class SyncPointStateCollection : public ISyncPointState + { + private: + std::vector + }; + +public: + SyncPoint() : state_( std::make_shared() ) + { } + + SyncPoint(const SyncPoint&) = default; + + SyncPoint& operator=(const SyncPoint&) = default; + + SyncPoint(SyncPoint&&) = default; + + SyncPoint& operator=(SyncPoint&&) = default; + + void Wait() + { + state_->Wait(); + } + + template + bool WaitFor(const std::chrono::duration& relTime) + { + return state_->WaitFor(relTime); + } + + template + bool WaitUntil(const std::chrono::duration& relTime) + { + return state_->WaitUntil(relTime); + } + + class Dependency + { + public: + Dependency() = default; + + // Construct from single sync point. + explicit Dependency(const SyncPoint& sp) : + state_( sp.state_ ) + { + state_->IncrementWaitCount(); + } + + // Construct from vector of other dependencies. + explicit Dependency(std::vector&& others) : + state_( sp.state_ ) + { + state_->IncrementWaitCount(); + } + + Dependency(const Dependency& other) : + state_( other.state_ ) + { + state_->IncrementWaitCount(); + } + + Dependency& operator=(const Dependency& other) + { + if (other.state_) + state_->IncrementWaitCount(); + + if (state_) + state_->DecrementWaitCount(); + + state_ = other.state_; + } + + Dependency(Dependency&& other) : + state_( std::move(other.state_) ) + { } + + Dependency& operator=(Dependency&& other) + { + if (state_) + state_->DecrementWaitCount(); + + state_ = std::move(other.state_); + } + + ~Dependency() + { + if (state_) + state_->DecrementWaitCount(); + } + + void Release() + { + if (state_) + { + state_->DecrementWaitCount(); + state_.reset(); + } + } + + bool IsReleased() const + { return state_ == nullptr; } + + private: + std::shared_ptr state_; + }; + +private: + std::shared_ptr state_; +}; + +/******************************************/ REACT_END /******************************************/ + +#endif // REACT_COMMON_SYNCPOINT_H_INCLUDED \ No newline at end of file diff --git a/include/react/common/utility.h b/include/react/common/utility.h new file mode 100644 index 00000000..d1ce975d --- /dev/null +++ b/include/react/common/utility.h @@ -0,0 +1,58 @@ + +// Copyright Sebastian Jeckel 2017. +// 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) + +#ifndef REACT_COMMON_UTIL_H_INCLUDED +#define REACT_COMMON_UTIL_H_INCLUDED + +#pragma once + +#include "react/detail/defs.h" + +#include +#include +#include + +/***************************************/ REACT_IMPL_BEGIN /**************************************/ + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// Helper to enable calling a function on each element of an argument pack. +/// We can't do f(args) ...; because ... expands with a comma. +/// But we can do nop_func(f(args) ...); +/////////////////////////////////////////////////////////////////////////////////////////////////// +template +inline void pass(TArgs&& ...) {} + +template +bool IsBitmaskSet(T flags, T mask) +{ + return (flags & mask) != (T)0; +} + +/****************************************/ REACT_IMPL_END /***************************************/ + +// Expand args by wrapping them in a dummy function +// Use comma operator to replace potential void return value with 0 +#define REACT_EXPAND_PACK(...) REACT_IMPL::pass((__VA_ARGS__ , 0) ...) + +#define REACT_DEFINE_BITMASK_OPERATORS(t) \ + inline t operator|(t lhs, t rhs) \ + { return static_cast(static_cast::type>(lhs) | static_cast::type>(rhs)); } \ + inline t operator&(t lhs, t rhs) \ + { return static_cast(static_cast::type>(lhs) & static_cast::type>(rhs)); } \ + inline t operator^(t lhs, t rhs) \ + { return static_cast(static_cast::type>(lhs) ^ static_cast::type>(rhs)); } \ + inline t operator~(t rhs) \ + { return static_cast(~static_cast::type>(rhs)); } \ + inline t& operator|=(t& lhs, t rhs) \ + { lhs = static_cast(static_cast::type>(lhs) | static_cast::type>(rhs)); return lhs; } \ + inline t& operator&=(t& lhs, t rhs) \ + { lhs = static_cast(static_cast::type>(lhs) & static_cast::type>(rhs)); return lhs; } \ + inline t& operator^=(t& lhs, t rhs) \ + { lhs = static_cast(static_cast::type>(lhs) ^ static_cast::type>(rhs)); return lhs; } + +// Bitmask helper + +#endif // REACT_COMMON_UTIL_H_INCLUDED \ No newline at end of file diff --git a/include/react/detail/Defs.h b/include/react/detail/Defs.h index 6bdda2e0..d1509c8c 100644 --- a/include/react/detail/Defs.h +++ b/include/react/detail/Defs.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2016. +// Copyright Sebastian Jeckel 2017. // 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) @@ -9,7 +9,6 @@ #pragma once -#include #include /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -21,15 +20,13 @@ #define REACT_IMPL_END REACT_END } #define REACT_IMPL REACT ::impl -/***************************************/ REACT_IMPL_BEGIN /**************************************/ +/*****************************************/ REACT_BEGIN /*****************************************/ // Type aliases using uint = unsigned int; using uchar = unsigned char; using std::size_t; -struct CtorTag { }; - -/****************************************/ REACT_IMPL_END /***************************************/ +/******************************************/ REACT_END /******************************************/ #endif // REACT_DETAIL_DEFS_H_INCLUDED \ No newline at end of file diff --git a/include/react/detail/ReactiveInput.h b/include/react/detail/ReactiveInput.h deleted file mode 100644 index d156b9fb..00000000 --- a/include/react/detail/ReactiveInput.h +++ /dev/null @@ -1,983 +0,0 @@ - -// Copyright Sebastian Jeckel 2016. -// 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) - -#if 0 - -#ifndef REACT_DETAIL_REACTIVEINPUT_H_INCLUDED -#define REACT_DETAIL_REACTIVEINPUT_H_INCLUDED - -#pragma once - -#include "react/detail/Defs.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "tbb/task.h" -#include "tbb/concurrent_queue.h" -#include "tbb/enumerable_thread_specific.h" -#include "tbb/queuing_mutex.h" - -#include "IReactiveEngine.h" -#include "ObserverBase.h" -#include "react/common/Concurrency.h" - -/***************************************/ REACT_IMPL_BEGIN /**************************************/ - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Forward declarations -/////////////////////////////////////////////////////////////////////////////////////////////////// -class IObserver; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Common types & constants -/////////////////////////////////////////////////////////////////////////////////////////////////// - -enum ETransactionFlags -{ - allow_merging = 1 << 0 -}; - -using TransactionFlagsT = std::underlying_type::type; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// EInputMode -/////////////////////////////////////////////////////////////////////////////////////////////////// -enum EInputMode -{ - consecutive_input, - concurrent_input -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// IContinuationTarget -/////////////////////////////////////////////////////////////////////////////////////////////////// -struct IContinuationTarget -{ - virtual void AsyncContinuation(TransactionFlagsT, const WaitingStatePtrT&, - TransactionFuncT&&) = 0; -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// ThreadLocalInputState -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -struct ThreadLocalInputState -{ - static REACT_TLS bool IsTransactionActive; -}; - -template -REACT_TLS bool ThreadLocalInputState::IsTransactionActive(false); - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// ContinuationManager -/////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface -template -class ContinuationManager -{ -public: - void StoreContinuation(IContinuationTarget& target, TransactionFlagsT flags, - TransactionFuncT&& cont); - - bool HasContinuations() const; - void StartContinuations(const WaitingStatePtrT& waitingStatePtr); - - void QueueObserverForDetach(IObserver& obs); - - template - void DetachQueuedObservers(); -}; - -// Non thread-safe implementation -template <> -class ContinuationManager -{ - struct Data_ - { - Data_(IContinuationTarget* target, TransactionFlagsT flags, TransactionFuncT&& func) : - Target( target ), - Flags( flags ), - Func( func ) - {} - - IContinuationTarget* Target; - TransactionFlagsT Flags; - TransactionFuncT Func; - }; - - using DataVectT = std::vector; - using ObsVectT = std::vector; - -public: - void StoreContinuation(IContinuationTarget& target, TransactionFlagsT flags, - TransactionFuncT&& cont) - { - storedContinuations_.emplace_back(&target, flags, std::move(cont)); - } - - bool HasContinuations() const - { - return !storedContinuations_.empty(); - } - - void StartContinuations(const WaitingStatePtrT& waitingStatePtr) - { - for (auto& t : storedContinuations_) - t.Target->AsyncContinuation(t.Flags, waitingStatePtr, std::move(t.Func)); - - storedContinuations_.clear(); - } - - // Todo: Move this somewhere else - void QueueObserverForDetach(IObserver& obs) - { - detachedObservers_.push_back(&obs); - } - - template - void DetachQueuedObservers() - { - for (auto* o : detachedObservers_) - o->UnregisterSelf(); - detachedObservers_.clear(); - } - -private: - DataVectT storedContinuations_; - ObsVectT detachedObservers_; -}; - -// Thread-safe implementation -template <> -class ContinuationManager -{ - struct Data_ - { - Data_(IContinuationTarget* target, TransactionFlagsT flags, TransactionFuncT&& func) : - Target( target ), - Flags( flags ), - Func( func ) - {} - - IContinuationTarget* Target; - TransactionFlagsT Flags; - TransactionFuncT Func; - }; - - using DataVecT = std::vector; - using ObsVectT = std::vector; - -public: - void StoreContinuation(IContinuationTarget& target, TransactionFlagsT flags, - TransactionFuncT&& cont) - { - storedContinuations_.local().emplace_back(&target, flags, std::move(cont)); - ++contCount_; - } - - bool HasContinuations() const - { - return contCount_ != 0; - } - - void StartContinuations(const WaitingStatePtrT& waitingStatePtr) - { - for (auto& v : storedContinuations_) - for (auto& t : v) - t.Target->AsyncContinuation(t.Flags, waitingStatePtr, std::move(t.Func)); - - storedContinuations_.clear(); - contCount_ = 0; - } - - void QueueObserverForDetach(IObserver& obs) - { - detachedObservers_.local().push_back(&obs); - } - - template - void DetachQueuedObservers() - { - for (auto& v : detachedObservers_) - { - for (auto* o : v) - o->UnregisterSelf(); - v.clear(); - } - } - -private: - tbb::enumerable_thread_specific storedContinuations_; - tbb::enumerable_thread_specific detachedObservers_; - - size_t contCount_ = 0; -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// TransactionQueue -/////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface -template -class TransactionQueue -{ -public: - class QueueEntry - { - public: - explicit QueueEntry(TransactionFlagsT flags); - - void RunMergedInputs(); - - size_t GetWaitingStatePtrCount() const; - void MoveWaitingStatePtrs(std::vector& out); - - void Release(); - - bool IsAsync() const; - }; - - template - bool TryMergeSync(F&& inputFunc); - - template - bool TryMergeAsync(F&& inputFunc, WaitingStatePtrT&& waitingStatePtr); - - void EnterQueue(QueueEntry& turn); - void ExitQueue(QueueEntry& turn); -}; - -// Non thread-safe implementation -template <> -class TransactionQueue -{ -public: - class QueueEntry - { - public: - explicit QueueEntry(TransactionFlagsT flags) {} - - void RunMergedInputs() {} - - size_t GetWaitingStatePtrCount() const { return 0; } - void MoveWaitingStatePtrs(std::vector& out) {} - - void Release() {} - - bool IsAsync() const { return false; } - }; - - template - bool TryMergeSync(F&& inputFunc) { return false; } - - template - bool TryMergeAsync(F&& inputFunc, WaitingStatePtrT&& waitingStatePtr) { return false; } - - void EnterQueue(QueueEntry& turn) {} - void ExitQueue(QueueEntry& turn) {} -}; - -// Thread-safe implementation -template <> -class TransactionQueue -{ -public: - class QueueEntry - { - public: - explicit QueueEntry(TransactionFlagsT flags) : - isMergeable_( (flags & allow_merging) != 0 ) - {} - - void Append(QueueEntry& tr) - { - successor_ = &tr; - tr.waitingState_.IncWaitCount(); - ++waitingStatePtrCount_; - } - - void WaitForUnblock() - { - waitingState_.Wait(); - } - - void RunMergedInputs() const - { - for (const auto& e : merged_) - e.InputFunc(); - } - - size_t GetWaitingStatePtrCount() const - { - return waitingStatePtrCount_; - } - - void MoveWaitingStatePtrs(std::vector& out) - { - if (waitingStatePtrCount_ == 0) - return; - - for (const auto& e : merged_) - if (e.WaitingStatePtr != nullptr) - out.push_back(std::move(e.WaitingStatePtr)); - - if (successor_) - { - out.push_back(WaitingStatePtrT( &successor_->waitingState_ )); - - // Ownership of successors waiting state has been transfered, - // we no longer need it - successor_ = nullptr; - } - - waitingStatePtrCount_ = 0; - } - - void Release() - { - if (waitingStatePtrCount_ == 0) - return; - - // Release merged - for (const auto& e : merged_) - if (e.WaitingStatePtr != nullptr) - e.WaitingStatePtr->DecWaitCount(); - - // Waiting state ptrs may point to stack of waiting threads. - // After decwaitcount, they may start running and terminate. - // Thus, clear merged ASAP because it now contains invalid ptrs. - merged_.clear(); - - // Release next thread in queue - if (successor_) - successor_->waitingState_.DecWaitCount(); - } - - template - bool TryMerge(F&& inputFunc, P&& waitingStatePtr) - { - if (!isMergeable_) - return false; - - // Only merge if target is still waiting - bool merged = waitingState_.RunIfWaiting([&] { - if (waitingStatePtr != nullptr) - { - waitingStatePtr->IncWaitCount(); - ++waitingStatePtrCount_; - } - - merged_.emplace_back(std::forward(inputFunc), std::forward

(waitingStatePtr)); - }); - - return merged; - } - - private: - struct MergedData - { - template - MergedData(F&& func, P&& waitingStatePtr) : - InputFunc( std::forward(func) ), - WaitingStatePtr( std::forward

(waitingStatePtr) ) - {} - - std::function InputFunc; - WaitingStatePtrT WaitingStatePtr; - }; - - using MergedDataVectT = std::vector; - - bool isMergeable_; - QueueEntry* successor_ = nullptr; - MergedDataVectT merged_; - UniqueWaitingState waitingState_; - size_t waitingStatePtrCount_ = 0; - }; - - template - bool TryMergeSync(F&& inputFunc) - { - bool merged = false; - - UniqueWaitingState st; - WaitingStatePtrT p( &st ); - - {// seqMutex_ - SeqMutexT::scoped_lock lock(seqMutex_); - - if (tail_) - merged = tail_->TryMerge(std::forward(inputFunc), p); - }// ~seqMutex_ - - if (merged) - p->Wait(); - - return merged; - } - - template - bool TryMergeAsync(F&& inputFunc, WaitingStatePtrT&& waitingStatePtr) - { - bool merged = false; - - {// seqMutex_ - SeqMutexT::scoped_lock lock(seqMutex_); - - if (tail_) - merged = tail_->TryMerge(std::forward(inputFunc), std::move(waitingStatePtr)); - }// ~seqMutex_ - - return merged; - } - - void EnterQueue(QueueEntry& tr) - { - {// seqMutex_ - SeqMutexT::scoped_lock lock(seqMutex_); - - if (tail_) - tail_->Append(tr); - - tail_ = &tr; - }// ~seqMutex_ - - tr.WaitForUnblock(); - } - - void ExitQueue(QueueEntry& tr) - { - {// seqMutex_ - SeqMutexT::scoped_lock lock(seqMutex_); - - if (tail_ == &tr) - tail_ = nullptr; - }// ~seqMutex_ - - tr.Release(); - } - -private: - using SeqMutexT = tbb::queuing_mutex; - - SeqMutexT seqMutex_; - QueueEntry* tail_ = nullptr; -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// AsyncWorker -/////////////////////////////////////////////////////////////////////////////////////////////////// -struct AsyncItem -{ - TransactionFlagsT Flags; - WaitingStatePtrT WaitingStatePtr; - TransactionFuncT Func; -}; - -// Interface -template -class AsyncWorker -{ -public: - AsyncWorker(InputManager& mgr); - - void PushItem(AsyncItem&& item); - - void PopItem(AsyncItem& item); - bool TryPopItem(AsyncItem& item); - - bool IncrementItemCount(size_t n); - bool DecrementItemCount(size_t n); - - void Start(); -}; - -// Disabled -template -struct AsyncWorker -{ -public: - AsyncWorker(InputManager& mgr) - {} - - void PushItem(AsyncItem&& item) { assert(false); } - - void PopItem(AsyncItem& item) { assert(false); } - bool TryPopItem(AsyncItem& item) { assert(false); return false; } - - bool IncrementItemCount(size_t n) { assert(false); return false; } - bool DecrementItemCount(size_t n) { assert(false); return false; } - - void Start() { assert(false); } -}; - -// Enabled -template -struct AsyncWorker -{ - using DataT = tbb::concurrent_bounded_queue; - - class WorkerTask : public tbb::task - { - public: - WorkerTask(InputManager& mgr) : - mgr_( mgr ) - {} - - tbb::task* execute() - { - mgr_.processAsyncQueue(); - return nullptr; - } - - private: - InputManager& mgr_; - }; - -public: - AsyncWorker(InputManager& mgr) : - mgr_( mgr ) - {} - - void PushItem(AsyncItem&& item) - { - data_.push(std::move(item)); - } - - void PopItem(AsyncItem& item) - { - data_.pop(item); - } - - bool TryPopItem(AsyncItem& item) - { - return data_.try_pop(item); - } - - bool IncrementItemCount(size_t n) - { - return count_.fetch_add(n, std::memory_order_relaxed) == 0; - } - - bool DecrementItemCount(size_t n) - { - return count_.fetch_sub(n, std::memory_order_relaxed) == n; - } - - void Start() - { - tbb::task::enqueue(*new(tbb::task::allocate_root()) WorkerTask(mgr_)); - } - -private: - DataT data_; - std::atomic count_{ 0 }; - - InputManager& mgr_; -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// InputManager -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -class InputManager : - public IContinuationTarget -{ -private: - // Select between thread-safe and non thread-safe implementations - using TransactionQueueT = TransactionQueue; - using QueueEntryT = typename TransactionQueueT::QueueEntry; - - using ContinuationManagerT = ContinuationManager; - using AsyncWorkerT = AsyncWorker; - - template - friend class AsyncWorker; - -public: - using TurnT = typename D::TurnT; - using Engine = typename D::Engine; - - InputManager() : - asyncWorker_(*this) - {} - - template - void DoTransaction(TransactionFlagsT flags, F&& func) - { - // Attempt to add input to another turn. - // If successful, blocks until other turn is done and returns. - bool canMerge = (flags & allow_merging) != 0; - if (canMerge && transactionQueue_.TryMergeSync(std::forward(func))) - return; - - bool shouldPropagate = false; - - QueueEntryT tr( flags ); - - transactionQueue_.EnterQueue(tr); - - // Phase 1 - Input admission - ThreadLocalInputState<>::IsTransactionActive = true; - - TurnT turn( nextTurnId(), flags ); - Engine::OnTurnAdmissionStart(turn); - func(); - tr.RunMergedInputs(); - Engine::OnTurnAdmissionEnd(turn); - - ThreadLocalInputState<>::IsTransactionActive = false; - - // Phase 2 - Apply input node changes - for (auto* p : changedInputs_) - if (p->ApplyInput(&turn)) - shouldPropagate = true; - changedInputs_.clear(); - - // Phase 3 - Propagate changes - if (shouldPropagate) - Engine::Propagate(turn); - - finalizeSyncTransaction(tr); - } - - template - void AsyncTransaction(TransactionFlagsT flags, const WaitingStatePtrT& waitingStatePtr, F&& func) - { - if (waitingStatePtr != nullptr) - waitingStatePtr->IncWaitCount(); - - asyncWorker_.PushItem(AsyncItem{ flags, waitingStatePtr, std::forward(func) }); - - if (asyncWorker_.IncrementItemCount(1)) - asyncWorker_.Start(); - } - - template - void AddInput(R& r, V&& v) - { - if (ThreadLocalInputState<>::IsTransactionActive) - { - addTransactionInput(r, std::forward(v)); - } - else - { - addSimpleInput(r, std::forward(v)); - } - } - - template - void ModifyInput(R& r, const F& func) - { - if (ThreadLocalInputState<>::IsTransactionActive) - { - modifyTransactionInput(r, func); - } - else - { - modifySimpleInput(r, func); - } - } - - //IContinuationTarget - virtual void AsyncContinuation(TransactionFlagsT flags, const WaitingStatePtrT& waitingStatePtr, TransactionFuncT&& cont) override - { - AsyncTransaction(flags, waitingStatePtr, std::move(cont)); - } - //~IContinuationTarget - - void StoreContinuation(IContinuationTarget& target, TransactionFlagsT flags, - TransactionFuncT&& cont) - { - continuationManager_.StoreContinuation(target, flags, std::move(cont)); - } - - void QueueObserverForDetach(IObserver& obs) - { - continuationManager_.QueueObserverForDetach(obs); - } - -private: - TurnIdT nextTurnId() - { - auto curId = nextTurnId_.fetch_add(1, std::memory_order_relaxed); - - if (curId == (std::numeric_limits::max)()) - nextTurnId_.fetch_sub((std::numeric_limits::max)()); - - return curId; - } - - // Create a turn with a single input - template - void addSimpleInput(R& r, V&& v) - { - QueueEntryT tr( 0 ); - - transactionQueue_.EnterQueue(tr); - - TurnT turn( nextTurnId(), 0 ); - Engine::OnTurnAdmissionStart(turn); - r.AddInput(std::forward(v)); - tr.RunMergedInputs(); - Engine::OnTurnAdmissionEnd(turn); - - if (r.ApplyInput(&turn)) - Engine::Propagate(turn); - - finalizeSyncTransaction(tr); - } - - template - void modifySimpleInput(R& r, const F& func) - { - QueueEntryT tr( 0 ); - - transactionQueue_.EnterQueue(tr); - - TurnT turn( nextTurnId(), 0 ); - Engine::OnTurnAdmissionStart(turn); - r.ModifyInput(func); - Engine::OnTurnAdmissionEnd(turn); - - // Return value, will always be true - r.ApplyInput(&turn); - - Engine::Propagate(turn); - - finalizeSyncTransaction(tr); - } - - void finalizeSyncTransaction(QueueEntryT& tr) - { - continuationManager_.template DetachQueuedObservers(); - - if (continuationManager_.HasContinuations()) - { - UniqueWaitingState st; - WaitingStatePtrT p( &st ); - - continuationManager_.StartContinuations(p); - - transactionQueue_.ExitQueue(tr); - - p->Wait(); - } - else - { - transactionQueue_.ExitQueue(tr); - } - } - - // This input is part of an active transaction - template - void addTransactionInput(R& r, V&& v) - { - r.AddInput(std::forward(v)); - changedInputs_.push_back(&r); - } - - template - void modifyTransactionInput(R& r, const F& func) - { - r.ModifyInput(func); - changedInputs_.push_back(&r); - } - - void processAsyncQueue() - { - AsyncItem item; - - std::vector waitingStatePtrs; - - bool skipPop = false; - - while (true) - { - size_t popCount = 0; - - if (!skipPop) - { - // Blocks if queue is empty. - // This should never happen, - // and if (maybe due to some memory access internals), only briefly - asyncWorker_.PopItem(item); - popCount++; - } - else - { - skipPop = false; - } - - // First try to merge to an existing synchronous item in the queue - bool canMerge = (item.Flags & allow_merging) != 0; - if (canMerge && transactionQueue_.TryMergeAsync( - std::move(item.Func), - std::move(item.WaitingStatePtr))) - continue; - - bool shouldPropagate = false; - - QueueEntryT tr( item.Flags ); - - // Blocks until turn is at the front of the queue - transactionQueue_.EnterQueue(tr); - - TurnT turn( nextTurnId(), item.Flags ); - - // Phase 1 - Input admission - ThreadLocalInputState<>::IsTransactionActive = true; - - Engine::OnTurnAdmissionStart(turn); - - // Input of current item - item.Func(); - - // Merged sync inputs that arrived while this item was queued - tr.RunMergedInputs(); - - // Save data, item might be re-used for next input - if (item.WaitingStatePtr != nullptr) - waitingStatePtrs.push_back(std::move(item.WaitingStatePtr)); - - // If the current item supports merging, try to add more mergeable inputs - // to this turn - if (canMerge) - { - uint extraCount = 0; - // Todo: Make configurable - while (extraCount < 1024 && asyncWorker_.TryPopItem(item)) - { - ++popCount; - - bool canMergeNext = (item.Flags & allow_merging) != 0; - if (canMergeNext) - { - item.Func(); - - if (item.WaitingStatePtr != nullptr) - waitingStatePtrs.push_back(std::move(item.WaitingStatePtr)); - - ++extraCount; - } - else - { - // We already popped an item we could not merge - // Process it in the next iteration - skipPop = true; - - // Break at first item that cannot be merged. - // We only allow merging of continuous ranges. - break; - } - } - } - - Engine::OnTurnAdmissionEnd(turn); - - ThreadLocalInputState<>::IsTransactionActive = false; - - // Phase 2 - Apply input node changes - for (auto* p : changedInputs_) - if (p->ApplyInput(&turn)) - shouldPropagate = true; - changedInputs_.clear(); - - // Phase 3 - Propagate changes - if (shouldPropagate) - Engine::Propagate(turn); - - continuationManager_.template DetachQueuedObservers(); - - // Has continuations? If so, status ptrs have to be passed on to - // continuation transactions - if (continuationManager_.HasContinuations()) - { - // Merge all waiting state ptrs for this transaction into a single vector - tr.MoveWaitingStatePtrs(waitingStatePtrs); - - // More than 1 waiting state -> create collection from vector - if (waitingStatePtrs.size() > 1) - { - WaitingStatePtrT p - ( - SharedWaitingStateCollection::Create(std::move(waitingStatePtrs)) - ); - - continuationManager_.StartContinuations(p); - - transactionQueue_.ExitQueue(tr); - p->DecWaitCount(); - } - // Exactly one status ptr -> pass it on directly - else if (waitingStatePtrs.size() == 1) - { - WaitingStatePtrT p( std::move(waitingStatePtrs[0]) ); - - continuationManager_.StartContinuations(p); - - transactionQueue_.ExitQueue(tr); - p->DecWaitCount(); - } - // No status ptrs - else - { - continuationManager_.StartContinuations(nullptr); - } - } - else - { - transactionQueue_.ExitQueue(tr); - - for (auto& p : waitingStatePtrs) - p->DecWaitCount(); - } - - waitingStatePtrs.clear(); - - // Stop this task if the number of items has just been decremented zero. - // A new task will be started by the thread that increments the item count from zero. - if (asyncWorker_.DecrementItemCount(popCount)) - break; - } - } - - TransactionQueueT transactionQueue_; - ContinuationManagerT continuationManager_; - AsyncWorkerT asyncWorker_; - - std::atomic nextTurnId_{ 0 }; - - std::vector changedInputs_; -}; - -template -class DomainSpecificInputManager -{ -public: - DomainSpecificInputManager() = delete; - - static InputManager& Instance() - { - static InputManager instance; - return instance; - } -}; - -/****************************************/ REACT_IMPL_END /***************************************/ - -#endif // REACT_DETAIL_REACTIVEINPUT_H_INCLUDED - -#endif \ No newline at end of file diff --git a/include/react/detail/graph/AlgorithmNodes.h b/include/react/detail/algorithm_nodes.h similarity index 68% rename from include/react/detail/graph/AlgorithmNodes.h rename to include/react/detail/algorithm_nodes.h index fdb925e1..94cdde7e 100644 --- a/include/react/detail/graph/AlgorithmNodes.h +++ b/include/react/detail/algorithm_nodes.h @@ -1,83 +1,24 @@ -// Copyright Sebastian Jeckel 2016. +// Copyright Sebastian Jeckel 2017. // 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) -#ifndef REACT_DETAIL_GRAPH_ALGORITHMNODES_H_INCLUDED -#define REACT_DETAIL_GRAPH_ALGORITHMNODES_H_INCLUDED +#ifndef REACT_DETAIL_ALGORITHM_NODES_H_INCLUDED +#define REACT_DETAIL_ALGORITHM_NODES_H_INCLUDED #pragma once -#include "react/detail/Defs.h" +#include "react/detail/defs.h" #include #include -#include "EventNodes.h" -#include "SignalNodes.h" +#include "event_nodes.h" +#include "signal_nodes.h" /***************************************/ REACT_IMPL_BEGIN /**************************************/ -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// AddIterateRangeWrapper -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -struct AddIterateRangeWrapper -{ - AddIterateRangeWrapper(const AddIterateRangeWrapper& other) = default; - - AddIterateRangeWrapper(AddIterateRangeWrapper&& other) : - MyFunc( std::move(other.MyFunc) ) - {} - - template - < - typename FIn, - class = typename DisableIfSame::type - > - explicit AddIterateRangeWrapper(FIn&& func) : - MyFunc( std::forward(func) ) - {} - - S operator()(EventRange range, S value, const TArgs& ... args) - { - for (const auto& e : range) - value = MyFunc(e, value, args ...); - - return value; - } - - F MyFunc; -}; - -template -struct AddIterateByRefRangeWrapper -{ - AddIterateByRefRangeWrapper(const AddIterateByRefRangeWrapper& other) = default; - - AddIterateByRefRangeWrapper(AddIterateByRefRangeWrapper&& other) : - MyFunc( std::move(other.MyFunc) ) - {} - - template - < - typename FIn, - class = typename DisableIfSame::type - > - explicit AddIterateByRefRangeWrapper(FIn&& func) : - MyFunc( std::forward(func) ) - {} - - void operator()(EventRange range, S& valueRef, const TArgs& ... args) - { - for (const auto& e : range) - MyFunc(e, valueRef, args ...); - } - - F MyFunc; -}; - /////////////////////////////////////////////////////////////////////////////////////////////////// /// IterateNode /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -101,12 +42,10 @@ class IterateNode : public SignalNode this->UnregisterMe(); } - virtual UpdateResult Update(TurnId turnId, size_t successorCount) override + virtual UpdateResult Update(TurnId turnId) noexcept override { S newValue = func_(EventRange( GetInternals(evnt_).Events() ), this->Value()); - GetInternals(evnt_).DecrementPendingSuccessorCount(); - if (! (newValue == this->Value())) { this->Value() = std::move(newValue); @@ -118,12 +57,6 @@ class IterateNode : public SignalNode } } - virtual const char* GetNodeType() const override - { return "Iterate"; } - - virtual int GetDependencyCount() const override - { return 1; } - private: F func_; Event evnt_; @@ -152,22 +85,14 @@ class IterateByRefNode : public SignalNode this->UnregisterMe(); } - virtual UpdateResult Update(TurnId turnId, size_t successorCount) override + virtual UpdateResult Update(TurnId turnId) noexcept override { func_(EventRange( GetInternals(evnt_).Events() ), this->Value()); - GetInternals(evnt_).DecrementPendingSuccessorCount(); - // Always assume change return UpdateResult::changed; } - virtual const char* GetNodeType() const override - { return "IterateByRefNode"; } - - virtual int GetDependencyCount() const override - { return 1; } - protected: F func_; Event evnt_; @@ -194,26 +119,24 @@ class SyncedIterateNode : public SignalNode ~SyncedIterateNode() { - apply([this] (const auto& ... syncs) { REACT_EXPAND_PACK(this->DetachFromMe(GetInternals(syncs).GetNodeId())); }, syncHolder_); + std::apply([this] (const auto& ... syncs) { REACT_EXPAND_PACK(this->DetachFromMe(GetInternals(syncs).GetNodeId())); }, syncHolder_); this->DetachFromMe(GetInternals(evnt_).GetNodeId()); this->UnregisterMe(); } - virtual UpdateResult Update(TurnId turnId, size_t successorCount) override + virtual UpdateResult Update(TurnId turnId) noexcept override { // Updates might be triggered even if only sync nodes changed. Ignore those. if (GetInternals(evnt_).Events().empty()) return UpdateResult::unchanged; - S newValue = apply( + S newValue = std::apply( [this] (const auto& ... syncs) { return func_(EventRange( GetInternals(evnt_).Events() ), this->Value(), GetInternals(syncs).Value() ...); }, syncHolder_); - GetInternals(evnt_).DecrementPendingSuccessorCount(); - if (! (newValue == this->Value())) { this->Value() = std::move(newValue); @@ -225,12 +148,6 @@ class SyncedIterateNode : public SignalNode } } - virtual const char* GetNodeType() const override - { return "SyncedIterate"; } - - virtual int GetDependencyCount() const override - { return 1 + sizeof...(TSyncs); } - private: F func_; Event evnt_; @@ -259,35 +176,27 @@ class SyncedIterateByRefNode : public SignalNode ~SyncedIterateByRefNode() { - apply([this] (const auto& ... syncs) { REACT_EXPAND_PACK(this->DetachFromMe(GetInternals(syncs).GetNodeId())); }, syncHolder_); + std::apply([this] (const auto& ... syncs) { REACT_EXPAND_PACK(this->DetachFromMe(GetInternals(syncs).GetNodeId())); }, syncHolder_); this->DetachFromMe(GetInternals(evnt_).GetNodeId()); this->UnregisterMe(); } - virtual UpdateResult Update(TurnId turnId, size_t successorCount) override + virtual UpdateResult Update(TurnId turnId) noexcept override { // Updates might be triggered even if only sync nodes changed. Ignore those. if (GetInternals(evnt_).Events().empty()) return UpdateResult::unchanged; - apply( + std::apply( [this] (const auto& ... args) { func_(EventRange( GetInternals(evnt_).Events() ), this->Value(), GetInternals(args).Value() ...); }, syncHolder_); - GetInternals(evnt_).DecrementPendingSuccessorCount(); - return UpdateResult::changed; } - virtual const char* GetNodeType() const override - { return "SyncedIterateByRef"; } - - virtual int GetDependencyCount() const override - { return 1 + sizeof...(TSyncs); } - private: F func_; Event events_; @@ -317,10 +226,7 @@ class HoldNode : public SignalNode this->UnregisterMe(); } - virtual const char* GetNodeType() const override - { return "HoldNode"; } - - virtual UpdateResult Update(TurnId turnId, size_t successorCount) override + virtual UpdateResult Update(TurnId turnId) noexcept override { bool changed = false; @@ -333,8 +239,6 @@ class HoldNode : public SignalNode changed = true; this->Value() = newValue; } - - GetInternals(evnt_).DecrementPendingSuccessorCount(); } if (changed) @@ -343,9 +247,6 @@ class HoldNode : public SignalNode return UpdateResult::unchanged; } - virtual int GetDependencyCount() const override - { return 1; } - private: Event evnt_; }; @@ -374,7 +275,7 @@ class SnapshotNode : public SignalNode this->UnregisterMe(); } - virtual UpdateResult Update(TurnId turnId, size_t successorCount) override + virtual UpdateResult Update(TurnId turnId) noexcept override { bool changed = false; @@ -387,8 +288,6 @@ class SnapshotNode : public SignalNode changed = true; this->Value() = newValue; } - - GetInternals(trigger_).DecrementPendingSuccessorCount(); } if (changed) @@ -397,12 +296,6 @@ class SnapshotNode : public SignalNode return UpdateResult::unchanged; } - virtual const char* GetNodeType() const override - { return "Snapshot"; } - - virtual int GetDependencyCount() const override - { return 2; } - private: Signal target_; Event trigger_; @@ -429,21 +322,13 @@ class MonitorNode : public EventStreamNode this->UnregisterMe(); } - virtual UpdateResult Update(TurnId turnId, size_t successorCount) override + virtual UpdateResult Update(TurnId turnId) noexcept override { this->Events().push_back(GetInternals(target_).Value()); - this->SetPendingSuccessorCount(successorCount); - return UpdateResult::changed; } - virtual const char* GetNodeType() const override - { return "Monitor"; } - - virtual int GetDependencyCount() const override - { return 1; } - private: Signal target_; }; @@ -472,16 +357,13 @@ class PulseNode : public EventStreamNode this->UnregisterMe(); } - virtual UpdateResult Update(TurnId turnId, size_t successorCount) override + virtual UpdateResult Update(TurnId turnId) noexcept override { for (size_t i = 0; i < GetInternals(trigger_).Events().size(); i++) this->Events().push_back(GetInternals(target_).Value()); - GetInternals(trigger_).DecrementPendingSuccessorCount(); - if (! this->Events().empty()) { - this->SetPendingSuccessorCount(successorCount); return UpdateResult::changed; } else @@ -490,12 +372,6 @@ class PulseNode : public EventStreamNode } } - virtual const char* GetNodeType() const override - { return "Pulse"; } - - virtual int GetDependencyCount() const override - { return 2; } - private: Signal target_; Event trigger_; @@ -503,4 +379,4 @@ class PulseNode : public EventStreamNode /****************************************/ REACT_IMPL_END /***************************************/ -#endif // REACT_DETAIL_GRAPH_ALGORITHMNODES_H_INCLUDED \ No newline at end of file +#endif // REACT_DETAIL_ALGORITHM_NODES_H_INCLUDED \ No newline at end of file diff --git a/include/react/detail/graph/EventNodes.h b/include/react/detail/event_nodes.h similarity index 66% rename from include/react/detail/graph/EventNodes.h rename to include/react/detail/event_nodes.h index e216b4b5..1a2e1cdf 100644 --- a/include/react/detail/graph/EventNodes.h +++ b/include/react/detail/event_nodes.h @@ -1,15 +1,15 @@ -// Copyright Sebastian Jeckel 2016. +// Copyright Sebastian Jeckel 2017. // 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) -#ifndef REACT_DETAIL_GRAPH_EVENTNODES_H_INCLUDED -#define REACT_DETAIL_GRAPH_EVENTNODES_H_INCLUDED +#ifndef REACT_DETAIL_EVENT_NODES_H_INCLUDED +#define REACT_DETAIL_EVENT_NODES_H_INCLUDED #pragma once -#include "react/detail/Defs.h" +#include "react/detail/defs.h" #include #include @@ -19,7 +19,7 @@ //#include "tbb/spin_mutex.h" -#include "GraphBase.h" +#include "node_base.h" #include "react/common/Types.h" /*****************************************/ REACT_BEGIN /*****************************************/ @@ -28,39 +28,10 @@ /// Iterators for event processing /////////////////////////////////////////////////////////////////////////////////////////////////// template -class EventRange -{ -public: - using const_iterator = typename std::vector::const_iterator; - using size_type = typename std::vector::size_type; - - EventRange() = delete; - - EventRange(const EventRange&) = default; - EventRange& operator=(const EventRange&) = default; - - explicit EventRange(const std::vector& data) : - data_( data ) - { } - - const_iterator begin() const - { return data_.begin(); } - - const_iterator end() const - { return data_.end(); } - - size_type GetSize() const - { return data_.size(); } - - bool IsEmpty() const - { return data_.empty(); } - -private: - const std::vector& data_; -}; +using EventValueList = std::vector; template -using EventSink = std::back_insert_iterator>; +using EventValueSink = std::back_insert_iterator>; /******************************************/ REACT_END /******************************************/ @@ -79,8 +50,6 @@ template class EventStreamNode : public NodeBase { public: - using StorageType = std::vector; - EventStreamNode(EventStreamNode&&) = default; EventStreamNode& operator=(EventStreamNode&&) = default; @@ -88,53 +57,27 @@ class EventStreamNode : public NodeBase EventStreamNode& operator=(const EventStreamNode&) = delete; explicit EventStreamNode(const Group& group) : - NodeBase( group ) - { } + EventStreamNode::NodeBase( group ) + { } - StorageType& Events() + EventValueList& Events() { return events_; } - const StorageType& Events() const + const EventValueList& Events() const { return events_; } - - void SetPendingSuccessorCount(size_t count) - { - if (count == 0) - { - // If there are no successors, buffer is cleared immediately. - events_.clear(); - } - else - { - // Otherwise, the last finished successor clears it. - pendingSuccessorCount_ = count; - } - } - - void DecrementPendingSuccessorCount() - { - // Not all predecessors of a node might be visited during a turn. - // In this case, the count is zero and the call to this function should be ignored. - if (pendingSuccessorCount_ == 0) - return; - - // Last successor to arrive clears the buffer. - if (pendingSuccessorCount_-- == 1) - events_.clear(); - } + virtual void Clear() noexcept override + { events_.clear(); } private: - StorageType events_; - - std::atomic pendingSuccessorCount_ = 0; + EventValueList events_; }; /////////////////////////////////////////////////////////////////////////////////////////////////// /// EventSourceNode /////////////////////////////////////////////////////////////////////////////////////////////////// -template -class EventSourceNode : public EventStreamNode +template +class EventSourceNode : public EventStreamNode { public: EventSourceNode(const Group& group) : @@ -148,23 +91,12 @@ class EventSourceNode : public EventStreamNode this->UnregisterMe(); } - virtual const char* GetNodeType() const override - { return "EventSource"; } - - virtual int GetDependencyCount() const override - { return 0; } - - virtual UpdateResult Update(TurnId turnId, size_t successorCount) override + virtual UpdateResult Update(TurnId turnId) noexcept override { if (! this->Events().empty()) - { - this->SetPendingSuccessorCount(successorCount); return UpdateResult::changed; - } else - { return UpdateResult::unchanged; - } } template @@ -175,13 +107,13 @@ class EventSourceNode : public EventStreamNode /////////////////////////////////////////////////////////////////////////////////////////////////// /// EventMergeNode /////////////////////////////////////////////////////////////////////////////////////////////////// -template -class EventMergeNode : public EventStreamNode +template +class EventMergeNode : public EventStreamNode { public: - EventMergeNode(const Group& group, const Event& ... deps) : + EventMergeNode(const Group& group, const Event& ... deps) : EventMergeNode::EventStreamNode( group ), - depHolder_( deps ... ) + inputs_( deps ... ) { this->RegisterMe(); REACT_EXPAND_PACK(this->AttachToMe(GetInternals(deps).GetNodeId())); @@ -189,43 +121,31 @@ class EventMergeNode : public EventStreamNode ~EventMergeNode() { - apply([this] (const auto& ... deps) { REACT_EXPAND_PACK(this->DetachFromMe(GetInternals(deps).GetNodeId())); }, depHolder_); + std::apply([this] (const auto& ... deps) + { REACT_EXPAND_PACK(this->DetachFromMe(GetInternals(deps).GetNodeId())); }, depHolder_); this->UnregisterMe(); } - virtual UpdateResult Update(TurnId turnId, size_t successorCount) override + virtual UpdateResult Update(TurnId turnId) noexcept override { - apply([this] (auto& ... deps) { REACT_EXPAND_PACK(MergeFromDep(deps)); }, depHolder_); + std::apply([this] (auto& ... deps) + { REACT_EXPAND_PACK(MergeFromDep(deps)); }, depHolder_); if (! this->Events().empty()) - { - this->SetPendingSuccessorCount(successorCount); return UpdateResult::changed; - } else - { return UpdateResult::unchanged; - } } - virtual const char* GetNodeType() const override - { return "EventMerge"; } - - virtual int GetDependencyCount() const override - { return sizeof...(TIns); } - private: template - void MergeFromDep(Event& dep) + void MergeFromInput(Event& dep) { - auto& depInternals = GetInternals(dep); - + EventInternals& depInternals = GetInternals(dep); this->Events().insert(this->Events().end(), depInternals.Events().begin(), depInternals.Events().end()); - - depInternals.DecrementPendingSuccessorCount(); } - std::tuple ...> depHolder_; + std::tuple ...> inputs_; }; /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -253,31 +173,18 @@ class EventSlotNode : public EventStreamNode GetGraphPtr()->UnregisterNode(inputNodeId_); } - virtual const char* GetNodeType() const override - { return "EventSlot"; } - - virtual int GetDependencyCount() const override - { return 2; } - - virtual UpdateResult Update(TurnId turnId, size_t successorCount) override + virtual UpdateResult Update(TurnId turnId) noexcept override { for (auto& e : inputs_) { const auto& events = GetInternals(e).Events(); this->Events().insert(this->Events().end(), events.begin(), events.end()); - - GetInternals(e).DecrementPendingSuccessorCount(); } if (! this->Events().empty()) - { - this->SetPendingSuccessorCount(successorCount); return UpdateResult::changed; - } else - { return UpdateResult::unchanged; - } } void AddInput(const Event& input) @@ -312,15 +219,9 @@ class EventSlotNode : public EventStreamNode { return inputNodeId_; } private: - struct VirtualInputNode : public IReactiveNode + struct VirtualInputNode : public IReactNode { - virtual const char* GetNodeType() const override - { return "EventSlotInput"; } - - virtual int GetDependencyCount() const override - { return 0; } - - virtual UpdateResult Update(TurnId turnId, size_t successorCount) override + virtual UpdateResult Update(TurnId turnId) noexcept override { return UpdateResult::changed; } }; @@ -353,29 +254,16 @@ class EventProcessingNode : public EventStreamNode this->UnregisterMe(); } - virtual UpdateResult Update(TurnId turnId, size_t successorCount) override + virtual UpdateResult Update(TurnId turnId) noexcept override { func_(EventRange( GetInternals(dep_).Events() ), std::back_inserter(this->Events())); - GetInternals(dep_).DecrementPendingSuccessorCount(); - if (! this->Events().empty()) - { - this->SetPendingSuccessorCount(successorCount); return UpdateResult::changed; - } else - { return UpdateResult::unchanged; - } } - virtual const char* GetNodeType() const override - { return "EventProcessing"; } - - virtual int GetDependencyCount() const override - { return 1; } - private: F func_; @@ -403,43 +291,30 @@ class SyncedEventProcessingNode : public EventStreamNode ~SyncedEventProcessingNode() { - apply([this] (const auto& ... syncs) { REACT_EXPAND_PACK(this->DetachFromMe(syncs->GetNodeId())); }, syncHolder_); + std::apply([this] (const auto& ... syncs) { REACT_EXPAND_PACK(this->DetachFromMe(syncs->GetNodeId())); }, syncHolder_); this->DetachFromMe(dep_->GetNodeId()); this->UnregisterMe(); } - virtual UpdateResult Update(TurnId turnId, size_t successorCount) override + virtual UpdateResult Update(TurnId turnId) noexcept override { // Updates might be triggered even if only sync nodes changed. Ignore those. if (dep_->Events().empty()) return UpdateResult::unchanged; - apply( + std::apply( [this] (const auto& ... syncs) { func_(EventRange( this->dep_->Events() ), std::back_inserter(this->Events()), syncs->Value() ...); }, syncHolder_); - dep_->DecrementPendingSuccessorCount(); - if (! this->Events().empty()) - { - this->SetPendingSuccessorCount(successorCount); return UpdateResult::changed; - } else - { return UpdateResult::unchanged; - } } - virtual const char* GetNodeType() const override - { return "SyncedEventProcessing"; } - - virtual int GetDependencyCount() const override - { return 1 + sizeof...(TSyncs); } - private: F func_; @@ -465,21 +340,21 @@ class EventJoinNode : public EventStreamNode> ~EventJoinNode() { - apply([this] (const auto& ... slots) { REACT_EXPAND_PACK(this->DetachFromMe(GetInternals(slots.source).GetNodeId())); }, slots_); + std::apply([this] (const auto& ... slots) { REACT_EXPAND_PACK(this->DetachFromMe(GetInternals(slots.source).GetNodeId())); }, slots_); this->UnregisterMe(); } - virtual UpdateResult Update(TurnId turnId, size_t successorCount) override + virtual UpdateResult Update(TurnId turnId) noexcept override { // Move events into buffers. - apply([this, turnId] (Slot& ... slots) { REACT_EXPAND_PACK(FetchBuffer(turnId, slots)); }, slots_); + std::apply([this, turnId] (Slot& ... slots) { REACT_EXPAND_PACK(FetchBuffer(turnId, slots)); }, slots_); while (true) { bool isReady = true; // All slots ready? - apply( + std::apply( [this, &isReady] (Slot& ... slots) { // Todo: combine return values instead @@ -491,7 +366,7 @@ class EventJoinNode : public EventStreamNode> break; // Pop values from buffers and emit tuple. - apply( + std::apply( [this] (Slot& ... slots) { this->Events().emplace_back(slots.buffer.front() ...); @@ -511,12 +386,6 @@ class EventJoinNode : public EventStreamNode> } } - virtual const char* GetNodeType() const override - { return "EventJoin"; } - - virtual int GetDependencyCount() const override - { return sizeof...(Ts); } - private: template struct Slot @@ -571,23 +440,14 @@ class EventLinkNode : public EventStreamNode void SetWeakSelfPtr(const std::weak_ptr& self) { linkOutput_.parent = self; } - virtual const char* GetNodeType() const override - { return "EventLink"; } + virtual UpdateResult Update(TurnId turnId) noexcept override + { return UpdateResult::changed; } - virtual int GetDependencyCount() const override - { return 1; } - - virtual UpdateResult Update(TurnId turnId, size_t successorCount) override - { - this->SetPendingSuccessorCount(successorCount); - return UpdateResult::changed; - } - - void SetEvents(EventLinkNode::EventStreamNode::StorageType&& events) + void SetEvents(EventValueList&& events) { this->Events() = std::move(events); } private: - struct VirtualOutputNode : public ILinkOutputNode + struct VirtualOutputNode : public IReactNode { VirtualOutputNode(const Event& depIn) : parent( ), @@ -596,23 +456,17 @@ class EventLinkNode : public EventStreamNode { auto& srcGraphPtr = GetInternals(srcGroup).GetGraphPtr(); nodeId = srcGraphPtr->RegisterNode(this, NodeCategory::linkoutput); - srcGraphPtr->OnNodeAttach(nodeId, GetInternals(dep).GetNodeId()); + srcGraphPtr->AttachNode(nodeId, GetInternals(dep).GetNodeId()); } ~VirtualOutputNode() { auto& srcGraphPtr = GetInternals(srcGroup).GetGraphPtr(); - srcGraphPtr->OnNodeDetach(nodeId, GetInternals(dep).GetNodeId()); + srcGraphPtr->DetachNode(nodeId, GetInternals(dep).GetNodeId()); srcGraphPtr->UnregisterNode(nodeId); } - virtual const char* GetNodeType() const override - { return "EventLinkOutput"; } - - virtual int GetDependencyCount() const override - { return 1; } - - virtual UpdateResult Update(TurnId turnId, size_t successorCount) override + virtual UpdateResult Update(TurnId turnId) noexcept override { return UpdateResult::changed; } virtual void CollectOutput(LinkOutputMap& output) override @@ -645,6 +499,42 @@ class EventLinkNode : public EventStreamNode VirtualOutputNode linkOutput_; }; +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// EventInternals +/////////////////////////////////////////////////////////////////////////////////////////////////// +template +class EventInternals +{ +public: + EventInternals(const EventInternals&) = default; + EventInternals& operator=(const EventInternals&) = default; + + EventInternals(EventInternals&&) = default; + EventInternals& operator=(EventInternals&&) = default; + + explicit EventInternals(std::shared_ptr>&& nodePtr) : + nodePtr_( std::move(nodePtr) ) + { } + + auto GetNodePtr() -> std::shared_ptr>& + { return nodePtr_; } + + auto GetNodePtr() const -> const std::shared_ptr>& + { return nodePtr_; } + + NodeId GetNodeId() const + { return nodePtr_->GetNodeId(); } + + EventValueList& Events() + { return nodePtr_->Events(); } + + const EventValueList& Events() const + { return nodePtr_->Events(); } + +private: + std::shared_ptr> nodePtr_; +}; + /****************************************/ REACT_IMPL_END /***************************************/ -#endif // REACT_DETAIL_GRAPH_EVENTNODES_H_INCLUDED \ No newline at end of file +#endif // REACT_DETAIL_EVENT_NODES_H_INCLUDED \ No newline at end of file diff --git a/include/react/detail/graph/PropagationMT.h b/include/react/detail/graph/PropagationMT.h deleted file mode 100644 index e69de29b..00000000 diff --git a/include/react/detail/graph/PropagationST.h b/include/react/detail/graph/PropagationST.h deleted file mode 100644 index 2fc0d048..00000000 --- a/include/react/detail/graph/PropagationST.h +++ /dev/null @@ -1,500 +0,0 @@ - -// Copyright Sebastian Jeckel 2016. -// 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) - -#ifndef REACT_DETAIL_GRAPH_PROPAGATIONST_H_INCLUDED -#define REACT_DETAIL_GRAPH_PROPAGATIONST_H_INCLUDED - -#pragma once - -#include "react/detail/Defs.h" - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "react/common/Containers.h" -#include "react/common/Types.h" -#include "react/detail/IReactiveGraph.h" - -/***************************************/ REACT_IMPL_BEGIN /**************************************/ - -template -class PtrCache -{ -public: - template - std::shared_ptr LookupOrCreate(const K& key, F&& createFunc) - { - std::lock_guard scopedLock(mutex_); - - auto it = map1_.find(key); - - if (it != map1_.end()) - { - if (auto ptr = it->second.lock()) - { - return std::static_pointer_cast(ptr); - } - } - - std::shared_ptr v = createFunc(); - auto res = map1_.insert({ key, std::weak_ptr{ v } }); - map2_[v.get()] = res.first; - return v; - } - - template - void Erase(V* ptr) - { - std::lock_guard scopedLock(mutex_); - - auto it = map2_.find((void*)ptr); - - if (it != map2_.end()) - { - map1_.erase(it->second); - map2_.erase(it); - } - } - -private: - std::mutex mutex_; - - using Map1Type = std::map>; - using Map2Type = std::unordered_map; - - Map1Type map1_; - Map2Type map2_; -}; - -class ReactiveGraph; - -class TransactionQueue -{ -public: - TransactionQueue(ReactiveGraph& graph) : - graph_( graph ) - { } - - TransactionQueue(const TransactionQueue&) = delete; - TransactionQueue& operator=(const TransactionQueue&) = delete; - - TransactionQueue(TransactionQueue&&) = default; - TransactionQueue& operator =(TransactionQueue&&) = default; - - template - void Push(TransactionFlags flags, F&& transaction) - { - transactions_.push(StoredTransaction{ flags, std::forward(transaction) }); - - if (count_.fetch_add(1, std::memory_order_relaxed) == 0) - tbb::task::enqueue(*new(tbb::task::allocate_root()) WorkerTask(*this)); - } - -private: - struct StoredTransaction - { - TransactionFlags flags; - std::function callback; - }; - - class WorkerTask : public tbb::task - { - public: - WorkerTask(TransactionQueue& parent) : - parent_( parent ) - { } - - tbb::task* execute() - { - parent_.ProcessQueue(); - return nullptr; - } - - private: - TransactionQueue& parent_; - }; - - void ProcessQueue(); - - size_t ProcessNextBatch(); - - tbb::concurrent_queue transactions_; - - std::atomic count_{ 0 }; - - ReactiveGraph& graph_; -}; - -class ReactiveGraph -{ -public: - using LinkCacheType = PtrCache>; - - NodeId RegisterNode(IReactiveNode* nodePtr, NodeCategory category); - void UnregisterNode(NodeId nodeId); - - void OnNodeAttach(NodeId node, NodeId parentId); - void OnNodeDetach(NodeId node, NodeId parentId); - - template - void AddInput(NodeId nodeId, F&& inputCallback); - - template - void DoTransaction(F&& transactionCallback); - - template - void EnqueueTransaction(TransactionFlags flags, F&& transactionCallback); - - LinkCacheType& GetLinkCache() - { return linkCache_; } - -private: - struct NodeData - { - NodeData() = default; - - NodeData(const NodeData&) = default; - NodeData& operator=(const NodeData&) = default; - - NodeData(IReactiveNode* nodePtrIn, NodeCategory categoryIn) : - nodePtr( nodePtrIn ), - category(categoryIn) - { } - - NodeCategory category = NodeCategory::normal; - - int level = 0; - int newLevel = 0 ; - bool queued = false; - - IReactiveNode* nodePtr = nullptr; - - std::vector successors; - }; - - class TopoQueue - { - public: - void Push(NodeId nodeId, int level) - { queueData_.emplace_back(nodeId, level); } - - bool FetchNext(); - - const std::vector& Next() const - { return nextData_; } - - bool IsEmpty() const - { return queueData_.empty(); } - - private: - using Entry = std::pair; - - std::vector queueData_; - std::vector nextData_; - - int minLevel_ = (std::numeric_limits::max)(); - }; - - void Propagate(); - void UpdateLinkNodes(); - - void ScheduleSuccessors(NodeData & node); - void InvalidateSuccessors(NodeData & node); - -private: - TransactionQueue transactionQueue_{ *this }; - - IndexedStorage nodeData_; - - TopoQueue scheduledNodes_; - std::vector changedInputs_; - LinkOutputMap scheduledLinkOutputs_; - - LinkCacheType linkCache_; - - bool isTransactionActive_ = false; -}; - -NodeId ReactiveGraph::RegisterNode(IReactiveNode* nodePtr, NodeCategory category) -{ - return nodeData_.Insert(NodeData{ nodePtr, category }); -} - -void ReactiveGraph::UnregisterNode(NodeId nodeId) -{ - nodeData_.Erase(nodeId); -} - -void ReactiveGraph::OnNodeAttach(NodeId nodeId, NodeId parentId) -{ - auto& node = nodeData_[nodeId]; - auto& parent = nodeData_[parentId]; - - parent.successors.push_back(nodeId); - - if (node.level <= parent.level) - node.level = parent.level + 1; -} - -void ReactiveGraph::OnNodeDetach(NodeId nodeId, NodeId parentId) -{ - auto& parent = nodeData_[parentId]; - auto& successors = parent.successors; - - successors.erase(std::find(successors.begin(), successors.end(), nodeId)); -} - -template -void ReactiveGraph::AddInput(NodeId nodeId, F&& inputCallback) -{ - auto& node = nodeData_[nodeId]; - auto* nodePtr = node.nodePtr; - - // This writes to the input buffer of the respective node. - inputCallback(); - - if (isTransactionActive_) - { - // If a transaction is active, don't propagate immediately. - // Instead, record the node and wait for more inputs. - changedInputs_.push_back(nodeId); - } - else - { - size_t successorCount = node.successors.size(); - - // Update the node. This applies the input buffer to the node value and checks if it changed. - if (nodePtr->Update(0, successorCount) == UpdateResult::changed) - { - // Propagate changes through the graph - ScheduleSuccessors(node); - - if (! scheduledNodes_.IsEmpty()) - Propagate(); - - if (! scheduledLinkOutputs_.empty()) - UpdateLinkNodes(); - } - } -} - -template -void ReactiveGraph::DoTransaction(F&& transactionCallback) -{ - // Transaction callback may add multiple inputs. - isTransactionActive_ = true; - std::forward(transactionCallback)(); - isTransactionActive_ = false; - - // Apply all buffered inputs. - for (NodeId nodeId : changedInputs_) - { - auto& node = nodeData_[nodeId]; - auto* nodePtr = node.nodePtr; - - size_t successorCount = node.successors.size(); - - if (nodePtr->Update(0, successorCount) == UpdateResult::changed) - { - if (node.category == NodeCategory::dyninput) - InvalidateSuccessors(node); - - ScheduleSuccessors(node); - } - } - - changedInputs_.clear(); - - // Propagate changes through the graph. - if (! scheduledNodes_.IsEmpty()) - Propagate(); - - if (! scheduledLinkOutputs_.empty()) - UpdateLinkNodes(); -} - -template -void ReactiveGraph::EnqueueTransaction(TransactionFlags flags, F&& transactionCallback) -{ - transactionQueue_.Push(flags, std::forward(transactionCallback)); -} - -void ReactiveGraph::Propagate() -{ - while (scheduledNodes_.FetchNext()) - { - for (NodeId nodeId : scheduledNodes_.Next()) - { - auto& node = nodeData_[nodeId]; - auto* nodePtr = node.nodePtr; - - if (node.level < node.newLevel) - { - // Re-schedule this node - node.level = node.newLevel; - InvalidateSuccessors(node); - scheduledNodes_.Push(nodeId, node.level); - continue; - } - - // Special handling for link output nodes. They have no successors and they don't have to be updated. - if (node.category == NodeCategory::linkoutput) - { - static_cast(node.nodePtr)->CollectOutput(scheduledLinkOutputs_); - continue; - } - - size_t successorCount = node.successors.size(); - - if (nodePtr->Update(0u, successorCount) == UpdateResult::changed) - { - ScheduleSuccessors(node); - } - - node.queued = false; - } - } -} - -void ReactiveGraph::UpdateLinkNodes() -{ - for (auto& e : scheduledLinkOutputs_) - { - e.first->EnqueueTransaction(TransactionFlags::none, - [inputs = std::move(e.second)] - { - for (auto& callback : inputs) - callback(); - }); - } - - scheduledLinkOutputs_.clear(); -} - -void ReactiveGraph::ScheduleSuccessors(NodeData& node) -{ - for (NodeId succId : node.successors) - { - auto& succ = nodeData_[succId]; - - if (!succ.queued) - { - succ.queued = true; - scheduledNodes_.Push(succId, succ.level); - } - } -} - -void ReactiveGraph::InvalidateSuccessors(NodeData& node) -{ - for (NodeId succId : node.successors) - { - auto& succ = nodeData_[succId]; - - if (succ.newLevel <= node.level) - succ.newLevel = node.level + 1; - } -} - -bool ReactiveGraph::TopoQueue::FetchNext() -{ - // Throw away previous values - nextData_.clear(); - - // Find min level of nodes in queue data - minLevel_ = (std::numeric_limits::max)(); - for (const auto& e : queueData_) - if (minLevel_ > e.second) - minLevel_ = e.second; - - // Swap entries with min level to the end - auto p = std::partition(queueData_.begin(), queueData_.end(), [t = minLevel_] (const Entry& e) { return t != e.second; }); - - // Move min level values to next data - nextData_.reserve(std::distance(p, queueData_.end())); - - for (auto it = p; it != queueData_.end(); ++it) - nextData_.push_back(it->first); - - // Truncate moved entries - queueData_.resize(std::distance(queueData_.begin(), p)); - - return !nextData_.empty(); -} - -void TransactionQueue::ProcessQueue() -{ - for (;;) - { - size_t popCount = ProcessNextBatch(); - if (count_.fetch_sub(popCount) == popCount) - return; - } -} - -size_t TransactionQueue::ProcessNextBatch() -{ - StoredTransaction curTransaction; - size_t popCount = 0; - bool canMerge = false; - bool skipPop = false; - bool isDone = false; - - // Outer loop. One transaction per iteration. - for (;;) - { - if (!skipPop) - { - if (!transactions_.try_pop(curTransaction)) - return popCount; - - canMerge = IsBitmaskSet(curTransaction.flags, TransactionFlags::allow_merging); - ++popCount; - } - else - { - skipPop = false; - } - - graph_.DoTransaction([&] - { - curTransaction.callback(); - - if (canMerge) - { - // Inner loop. Mergeable transactions are merged - for (;;) - { - if (transactions_.try_pop(curTransaction)) - return; - - canMerge = IsBitmaskSet(curTransaction.flags, TransactionFlags::allow_merging); - ++popCount; - - if (!canMerge) - { - skipPop = true; - return; - } - - curTransaction.callback(); - } - } - }); - } -} - -/****************************************/ REACT_IMPL_END /***************************************/ - -#endif // REACT_DETAIL_GRAPH_PROPAGATIONST_H_INCLUDED \ No newline at end of file diff --git a/include/react/detail/graph_impl.h b/include/react/detail/graph_impl.h new file mode 100644 index 00000000..133ffbe6 --- /dev/null +++ b/include/react/detail/graph_impl.h @@ -0,0 +1,224 @@ + +// Copyright Sebastian Jeckel 2017. +// 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) + +#ifndef REACT_DETAIL_PROPAGATION_H_INCLUDED +#define REACT_DETAIL_PROPAGATION_H_INCLUDED + +#pragma once + +#include "react/detail/defs.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "react/common/ptrcache.h" +#include "react/common/slotmap.h" +#include "react/common/syncpoint.h" +#include "react/detail/graph_interface.h" + +/***************************************/ REACT_IMPL_BEGIN /**************************************/ + +class ReactGraph; + +class TransactionQueue +{ +public: + TransactionQueue(ReactGraph& graph) : + graph_( graph ) + { } + + TransactionQueue(const TransactionQueue&) = delete; + TransactionQueue& operator=(const TransactionQueue&) = delete; + + TransactionQueue(TransactionQueue&&) = default; + TransactionQueue& operator =(TransactionQueue&&) = default; + + template + void Push(F&& func, SyncPoint::Dependency dep, TransactionFlags flags) + { + transactions_.push(StoredTransaction{ std::forward(transaction), std::move(dep), flags }); + + if (count_.fetch_add(1, std::memory_order_release) == 0) + tbb::task::enqueue(*new(tbb::task::allocate_root()) WorkerTask(*this)); + } + +private: + struct StoredTransaction + { + std::function func; + SyncPoint::DependencyList deps; + TransactionFlags flags; + }; + + class WorkerTask : public tbb::task + { + public: + WorkerTask(TransactionQueue& parent) : + parent_( parent ) + { } + + tbb::task* execute() + { + parent_.ProcessQueue(); + return nullptr; + } + + private: + TransactionQueue& parent_; + }; + + void ProcessQueue(); + + size_t ProcessNextBatch(); + + tbb::concurrent_queue transactions_; + + std::atomic count_{ 0 }; + + ReactGraph& graph_; +}; + +class ReactGraph +{ +public: + using LinkCache = WeakPtrCache; + + NodeId RegisterNode(IReactNode* nodePtr, NodeCategory category); + void UnregisterNode(NodeId nodeId); + + void AttachNode(NodeId node, NodeId parentId); + void DetachNode(NodeId node, NodeId parentId); + + template + void PushInput(NodeId nodeId, F&& inputCallback); + + void PushDependency(SyncPoint::Dependency dep); + + template + void DoTransaction(F&& transactionCallback); + + template + void EnqueueTransaction(F&& func, SyncPoint::DependencyList&& deps, TransactionFlags flags); + + LinkCache& GetLinkCache() + { return linkCache_; } + +private: + struct NodeData + { + NodeData() = default; + + NodeData(const NodeData&) = default; + NodeData& operator=(const NodeData&) = default; + + NodeData(IReactNode* nodePtrIn, NodeCategory categoryIn) : + nodePtr( nodePtrIn ), + category(categoryIn) + { } + + NodeCategory category = NodeCategory::normal; + + int level = 0; + int newLevel = 0 ; + bool queued = false; + + IReactNode* nodePtr = nullptr; + + std::vector successors; + }; + + class TopoQueue + { + public: + void Push(NodeId nodeId, int level) + { queueData_.emplace_back(nodeId, level); } + + bool FetchNext(); + + const std::vector& Next() const + { return nextData_; } + + bool IsEmpty() const + { return queueData_.empty(); } + + private: + using Entry = std::pair; + + std::vector queueData_; + std::vector nextData_; + + int minLevel_ = (std::numeric_limits::max)(); + }; + + void Propagate(); + void UpdateLinkNodes(); + + void ScheduleSuccessors(NodeData & node); + void RecalculateSuccessorLevels(NodeData & node); + +private: + TransactionQueue transactionQueue_{ *this }; + + SlotMap nodeData_; + + TopoQueue scheduledNodes_; + + std::vector changedInputs_; + std::vector changedNodes_; + + std::vector curDependencies_; + + LinkOutputMap scheduledLinkOutputs_; + + LinkCache linkCache_; + + bool isTransactionActive_ = false; +}; + +template +void ReactGraph::PushInput(NodeId nodeId, F&& inputCallback) +{ + auto& node = nodeData_[nodeId]; + auto* nodePtr = node.nodePtr; + + // This writes to the input buffer of the respective node. + std::forward(inputCallback)(); + + changedInputs_.push_back(nodeId); + + if (!isTransactionActive_) + Propagate(); +} + +template +void ReactGraph::DoTransaction(F&& transactionCallback) +{ + // Transaction callback may add multiple inputs. + isTransactionActive_ = true; + std::forward(transactionCallback)(); + isTransactionActive_ = false; + + Propagate(); +} + +template +void ReactGraph::EnqueueTransaction(F&& func, SyncPoint::DependencyList&& deps, TransactionFlags flags) +{ + transactionQueue_.Push(std::forward(func), std::move(deps), flags); +} + +/****************************************/ REACT_IMPL_END /***************************************/ + +#endif // REACT_DETAIL_PROPAGATION_H_INCLUDED \ No newline at end of file diff --git a/include/react/detail/IReactiveGraph.h b/include/react/detail/graph_interface.h similarity index 63% rename from include/react/detail/IReactiveGraph.h rename to include/react/detail/graph_interface.h index 85f3d253..6fa51f89 100644 --- a/include/react/detail/IReactiveGraph.h +++ b/include/react/detail/graph_interface.h @@ -1,24 +1,24 @@ -// Copyright Sebastian Jeckel 2016. +// Copyright Sebastian Jeckel 2017. // 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) -#ifndef REACT_DETAIL_IREACTIVEENGINE_H_INCLUDED -#define REACT_DETAIL_IREACTIVEENGINE_H_INCLUDED +#ifndef REACT_DETAIL_GRAPH_INTERFACE_H_INCLUDED +#define REACT_DETAIL_GRAPH_INTERFACE_H_INCLUDED #pragma once -#include "react/detail/Defs.h" +#include "react/detail/defs.h" #include #include #include #include -#include "react/API.h" -#include "react/common/Types.h" -#include "react/common/Util.h" +#include "react/api.h" +#include "react/common/types.h" +#include "react/common/utility.h" /***************************************/ REACT_IMPL_BEGIN /**************************************/ @@ -48,29 +48,29 @@ enum class NodeCategory linkoutput }; -class ReactiveGraph; +class ReactGraph; +struct IReactNode; + +using LinkOutputMap = std::unordered_map>>; /////////////////////////////////////////////////////////////////////////////////////////////////// -/// IReactiveNode +/// IReactNode /////////////////////////////////////////////////////////////////////////////////////////////////// -struct IReactiveNode +struct IReactNode { - virtual ~IReactiveNode() = default; - - virtual const char* GetNodeType() const = 0; + virtual ~IReactNode() = default; - virtual UpdateResult Update(TurnId turnId, size_t successorCount) = 0; + virtual UpdateResult Update(TurnId turnId) noexcept = 0; + + virtual void Clear() noexcept + { } - virtual int GetDependencyCount() const = 0; + virtual void CollectOutput(LinkOutputMap& output) + { } }; -using LinkOutputMap = std::unordered_map>>; -struct ILinkOutputNode : public IReactiveNode -{ - virtual void CollectOutput(LinkOutputMap& output) = 0; -}; /****************************************/ REACT_IMPL_END /***************************************/ -#endif // REACT_DETAIL_IREACTIVEENGINE_H_INCLUDED \ No newline at end of file +#endif // REACT_DETAIL_GRAPH_INTERFACE_H_INCLUDED \ No newline at end of file diff --git a/include/react/detail/graph/GraphBase.h b/include/react/detail/node_base.h similarity index 65% rename from include/react/detail/graph/GraphBase.h rename to include/react/detail/node_base.h index 65f8d1f7..6345d431 100644 --- a/include/react/detail/graph/GraphBase.h +++ b/include/react/detail/node_base.h @@ -1,37 +1,47 @@ -// Copyright Sebastian Jeckel 2016. +// Copyright Sebastian Jeckel 2017. // 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) -#ifndef REACT_DETAIL_GRAPH_GRAPHBASE_H_INCLUDED -#define REACT_DETAIL_GRAPH_GRAPHBASE_H_INCLUDED +#ifndef REACT_DETAIL_NODE_BASE_H_INCLUDED +#define REACT_DETAIL_NODE_BASE_H_INCLUDED #pragma once -#include "react/detail/Defs.h" +#include "react/detail/defs.h" #include #include #include -#include "react/common/Types.h" -#include "react/common/Util.h" -#include "react/detail/IReactiveGraph.h" +#include "react/common/types.h" +#include "react/common/utility.h" +#include "react/detail/graph_interface.h" /***************************************/ REACT_IMPL_BEGIN /**************************************/ -class ReactiveGraph; +class ReactGraph; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// CreateWrappedNode +/////////////////////////////////////////////////////////////////////////////////////////////////// +template +static RET CreateWrappedNode(ARGS&& ... args) +{ + auto node = std::make_shared(std::forward(args) ...); + return RET(std::move(node)); +} /////////////////////////////////////////////////////////////////////////////////////////////////// /// NodeBase /////////////////////////////////////////////////////////////////////////////////////////////////// -class NodeBase : public IReactiveNode +class NodeBase : public IReactNode { public: NodeBase(const Group& group) : group_( group ) - { } + { } NodeBase(const NodeBase&) = delete; NodeBase& operator=(const NodeBase&) = delete; @@ -65,10 +75,10 @@ class NodeBase : public IReactiveNode { return group_; } protected: - auto GetGraphPtr() const -> const std::shared_ptr& + auto GetGraphPtr() const -> const std::shared_ptr& { return GetInternals(group_).GetGraphPtr(); } - auto GetGraphPtr() -> std::shared_ptr& + auto GetGraphPtr() -> std::shared_ptr& { return GetInternals(group_).GetGraphPtr(); } void RegisterMe(NodeCategory category = NodeCategory::normal) @@ -78,10 +88,10 @@ class NodeBase : public IReactiveNode { GetGraphPtr()->UnregisterNode(nodeId_); } void AttachToMe(NodeId otherNodeId) - { GetGraphPtr()->OnNodeAttach(nodeId_, otherNodeId); } + { GetGraphPtr()->AttachNode(nodeId_, otherNodeId); } void DetachFromMe(NodeId otherNodeId) - { GetGraphPtr()->OnNodeDetach(nodeId_, otherNodeId); } + { GetGraphPtr()->DetachNode(nodeId_, otherNodeId); } private: NodeId nodeId_; @@ -91,4 +101,4 @@ class NodeBase : public IReactiveNode /****************************************/ REACT_IMPL_END /***************************************/ -#endif // REACT_DETAIL_GRAPH_GRAPHBASE_H_INCLUDED \ No newline at end of file +#endif // REACT_DETAIL_NODE_BASE_H_INCLUDED \ No newline at end of file diff --git a/include/react/detail/graph/ObserverNodes.h b/include/react/detail/observer_nodes.h similarity index 69% rename from include/react/detail/graph/ObserverNodes.h rename to include/react/detail/observer_nodes.h index 695c0792..35c160b1 100644 --- a/include/react/detail/graph/ObserverNodes.h +++ b/include/react/detail/observer_nodes.h @@ -1,23 +1,21 @@ -// Copyright Sebastian Jeckel 2016. +// Copyright Sebastian Jeckel 2017. // 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) -#ifndef REACT_DETAIL_GRAPH_OBSERVERNODES_H_INCLUDED -#define REACT_DETAIL_GRAPH_OBSERVERNODES_H_INCLUDED +#ifndef REACT_DETAIL_OBSERVER_NODES_H_INCLUDED +#define REACT_DETAIL_OBSERVER_NODES_H_INCLUDED #pragma once -#include "react/detail/Defs.h" -#include "react/API.h" +#include "react/detail/defs.h" +#include "react/api.h" #include #include -#include "GraphBase.h" - -#include "react/detail/ReactiveInput.h" +#include "node_base.h" /***************************************/ REACT_IMPL_BEGIN /**************************************/ @@ -36,9 +34,9 @@ class EventStreamNode; class ObserverNode : public NodeBase { public: - ObserverNode(const Group& group) : + explicit ObserverNode(const Group& group) : ObserverNode::NodeBase( group ) - { } + { } }; /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -60,19 +58,14 @@ class SignalObserverNode : public ObserverNode ~SignalObserverNode() { - apply([this] (const auto& ... deps) { REACT_EXPAND_PACK(this->DetachFromMe(GetInternals(deps).GetNodeId())); }, depHolder_); + std::apply([this] (const auto& ... deps) + { REACT_EXPAND_PACK(this->DetachFromMe(GetInternals(deps).GetNodeId())); }, depHolder_); this->UnregisterMe(); } - virtual const char* GetNodeType() const override - { return "SignalObserver"; } - - virtual int GetDependencyCount() const override - { return sizeof...(TDeps); } - - virtual UpdateResult Update(TurnId turnId, size_t successorCount) override + virtual UpdateResult Update(TurnId turnId) noexcept override { - apply([this] (const auto& ... deps) { this->func_(GetInternals(deps).Value() ...); }, depHolder_); + std::apply([this] (const auto& ... deps) { this->func_(GetInternals(deps).Value() ...); }, depHolder_); return UpdateResult::unchanged; } @@ -105,16 +98,9 @@ class EventObserverNode : public ObserverNode this->UnregisterMe(); } - virtual const char* GetNodeType() const override - { return "EventObserver"; } - - virtual int GetDependencyCount() const override - { return 1; } - - virtual UpdateResult Update(TurnId turnId, size_t successorCount) override + virtual UpdateResult Update(TurnId turnId) noexcept override { - func_(EventRange( GetInternals(subject_).Events() )); - GetInternals(subject_).DecrementPendingSuccessorCount(); + func_(GetInternals(subject_).Events()); return UpdateResult::unchanged; } @@ -145,26 +131,20 @@ class SyncedEventObserverNode : public ObserverNode ~SyncedEventObserverNode() { - apply([this] (const auto& ... syncs) { REACT_EXPAND_PACK(this->DetachFromMe(GetInternals(syncs).GetNodeId())); }, syncHolder_); + std::apply([this] (const auto& ... syncs) + { REACT_EXPAND_PACK(this->DetachFromMe(GetInternals(syncs).GetNodeId())); }, syncHolder_); this->DetachFromMe(GetInternals(subject_).GetNodeId()); this->UnregisterMe(); } - virtual const char* GetNodeType() const override - { return "SyncedEventObserver"; } - - virtual int GetDependencyCount() const override - { return 1 + sizeof...(TSyncs); } - - virtual UpdateResult Update(TurnId turnId, size_t successorCount) override + virtual UpdateResult Update(TurnId turnId) noexcept override { // Updates might be triggered even if only sync nodes changed. Ignore those. if (GetInternals(this->subject_).Events().empty()) return UpdateResult::unchanged; - apply([this] (const auto& ... syncs) { func_(EventRange( GetInternals(this->subject_).Events() ), GetInternals(syncs).Value() ...); }, syncHolder_); - - GetInternals(subject_).DecrementPendingSuccessorCount(); + std::apply([this] (const auto& ... syncs) + { func_(EventRange( GetInternals(this->subject_).Events() ), GetInternals(syncs).Value() ...); }, syncHolder_); return UpdateResult::unchanged; } @@ -179,4 +159,4 @@ class SyncedEventObserverNode : public ObserverNode /****************************************/ REACT_IMPL_END /***************************************/ -#endif // REACT_DETAIL_GRAPH_OBSERVERNODES_H_INCLUDED \ No newline at end of file +#endif // REACT_DETAIL_OBSERVER_NODES_H_INCLUDED \ No newline at end of file diff --git a/include/react/detail/graph/SignalNodes.h b/include/react/detail/signal_nodes.h similarity index 74% rename from include/react/detail/graph/SignalNodes.h rename to include/react/detail/signal_nodes.h index 268faf7c..f97dc908 100644 --- a/include/react/detail/graph/SignalNodes.h +++ b/include/react/detail/signal_nodes.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2016. +// Copyright Sebastian Jeckel 2017. // 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) @@ -9,14 +9,14 @@ #ifndef REACT_DETAIL_GRAPH_SIGNALNODES_H_INCLUDED #define REACT_DETAIL_GRAPH_SIGNALNODES_H_INCLUDED -#include "react/detail/Defs.h" +#include "react/detail/defs.h" #include #include #include #include -#include "GraphBase.h" +#include "node_base.h" /***************************************/ REACT_IMPL_BEGIN /**************************************/ @@ -42,13 +42,13 @@ class SignalNode : public NodeBase explicit SignalNode(const Group& group) : SignalNode::NodeBase( group ), value_( ) - { } + { } template SignalNode(const Group& group, T&& value) : SignalNode::NodeBase( group ), value_( std::forward(value) ) - { } + { } S& Value() { return value_; } @@ -87,13 +87,7 @@ class VarSignalNode : public SignalNode this->UnregisterMe(); } - virtual const char* GetNodeType() const override - { return "VarSignal"; } - - virtual int GetDependencyCount() const override - { return 0; } - - virtual UpdateResult Update(TurnId turnId, size_t successorCount) override + virtual UpdateResult Update(TurnId turnId) noexcept override { if (isInputAdded_) { @@ -149,7 +143,7 @@ class VarSignalNode : public SignalNode // in ApplyInput else { - func(newValue_); + func(newValue_); } } @@ -178,21 +172,17 @@ class SignalFuncNode : public SignalNode ~SignalFuncNode() { - apply([this] (const auto& ... deps) { REACT_EXPAND_PACK(this->DetachFromMe(GetInternals(deps).GetNodePtr()->GetNodeId())); }, depHolder_); + std::apply([this] (const auto& ... deps) + { REACT_EXPAND_PACK(this->DetachFromMe(GetInternals(deps).GetNodePtr()->GetNodeId())); }, depHolder_); this->UnregisterMe(); } - virtual const char* GetNodeType() const override - { return "SignalFunc"; } - - virtual int GetDependencyCount() const override - { return sizeof...(TDeps); } - - virtual UpdateResult Update(TurnId turnId, size_t successorCount) override + virtual UpdateResult Update(TurnId turnId) noexcept override { bool changed = false; - S newValue = apply([this] (const auto& ... deps) { return this->func_(GetInternals(deps).Value() ...); }, depHolder_); + S newValue = std::apply([this] (const auto& ... deps) + { return this->func_(GetInternals(deps).Value() ...); }, depHolder_); if (! (this->Value() == newValue)) { @@ -208,7 +198,6 @@ class SignalFuncNode : public SignalNode private: F func_; - std::tuple ...> depHolder_; }; @@ -224,8 +213,8 @@ class SignalSlotNode : public SignalNode input_( dep ) { inputNodeId_ = GetGraphPtr()->RegisterNode(&slotInput_, NodeCategory::dyninput); + this->RegisterMe(); - this->AttachToMe(inputNodeId_); this->AttachToMe(GetInternals(dep).GetNodeId()); } @@ -234,18 +223,12 @@ class SignalSlotNode : public SignalNode { this->DetachFromMe(GetInternals(input_).GetNodeId()); this->DetachFromMe(inputNodeId_); - this->UnregisterMe(); + GetGraphPtr()->UnregisterNode(inputNodeId_); } - virtual const char* GetNodeType() const override - { return "SignalSlot"; } - - virtual int GetDependencyCount() const override - { return 2; } - - virtual UpdateResult Update(TurnId turnId, size_t successorCount) override + virtual UpdateResult Update(TurnId turnId) noexcept override { if (! (this->Value() == GetInternals(input_).Value())) { @@ -273,20 +256,13 @@ class SignalSlotNode : public SignalNode { return inputNodeId_; } private: - struct VirtualInputNode : public IReactiveNode + struct VirtualInputNode : public IReactNode { - virtual const char* GetNodeType() const override - { return "SignalSlotInput"; } - - virtual int GetDependencyCount() const override - { return 0; } - - virtual UpdateResult Update(TurnId turnId, size_t successorCount) override + virtual UpdateResult Update(TurnId turnId) noexcept override { return UpdateResult::changed; } }; - Signal input_; - + Signal input_; NodeId inputNodeId_; VirtualInputNode slotInput_; @@ -301,13 +277,24 @@ class SignalLinkNode : public SignalNode public: SignalLinkNode(const Group& group, const Signal& dep) : SignalLinkNode::SignalNode( group, GetInternals(dep).Value() ), - linkOutput_( dep ) + dep_ ( dep ) { this->RegisterMe(NodeCategory::input); + + auto& srcGraphPtr = GetInternals(srcGroup).GetGraphPtr(); + outputNodeId_ = srcGraphPtr->RegisterNode(this, NodeCategory::linkoutput); + + srcGraphPtr->AttachNode(outputNodeId_, GetInternals(dep).GetNodeId()); } ~SignalLinkNode() { + this->DetachFromMe(GetInternals(dep_).GetNodeId()); + + auto& srcGraphPtr = GetInternals(srcGroup).GetGraphPtr(); + srcGraphPtr->DetachNode(outputNodeId_, GetInternals(dep_).GetNodeId()); + srcGraphPtr->UnregisterNode(outputNodeId_); + auto& linkCache = GetGraphPtr()->GetLinkCache(); linkCache.Erase(this); @@ -317,46 +304,16 @@ class SignalLinkNode : public SignalNode void SetWeakSelfPtr(const std::weak_ptr& self) { linkOutput_.parent = self; } - virtual const char* GetNodeType() const override - { return "SignalLink"; } - - virtual int GetDependencyCount() const override - { return 1; } - - virtual UpdateResult Update(TurnId turnId, size_t successorCount) override + virtual UpdateResult Update(TurnId turnId) noexcept override { return UpdateResult::changed; } - template - void SetValue(T&& newValue) - { this->Value() = std::forward(newValue); } + void SetValue(S&& newValue) + { this->Value() = std::move(newValue); } private: - struct VirtualOutputNode : public ILinkOutputNode + struct VirtualOutputNode : public IReactNode { - VirtualOutputNode(const Signal& depIn) : - parent( ), - dep( depIn ), - srcGroup( depIn.GetGroup() ) - { - auto& srcGraphPtr = GetInternals(srcGroup).GetGraphPtr(); - nodeId = srcGraphPtr->RegisterNode(this, NodeCategory::linkoutput); - srcGraphPtr->OnNodeAttach(nodeId, GetInternals(dep).GetNodeId()); - } - - ~VirtualOutputNode() - { - auto& srcGraphPtr = GetInternals(srcGroup).GetGraphPtr(); - srcGraphPtr->OnNodeDetach(nodeId, GetInternals(dep).GetNodeId()); - srcGraphPtr->UnregisterNode(nodeId); - } - - virtual const char* GetNodeType() const override - { return "SignalLinkOutput"; } - - virtual int GetDependencyCount() const override - { return 1; } - - virtual UpdateResult Update(TurnId turnId, size_t successorCount) override + virtual UpdateResult Update(TurnId turnId) noexcept override { return UpdateResult::changed; } virtual void CollectOutput(LinkOutputMap& output) override @@ -365,7 +322,7 @@ class SignalLinkNode : public SignalNode { auto* rawPtr = p->GetGraphPtr().get(); output[rawPtr].push_back( - [storedParent = std::move(p), storedValue = GetInternals(dep).Value()] + [storedParent = std::move(p), storedValue = GetInternals(p->dep_).Value()] () mutable -> void { NodeId nodeId = storedParent->GetNodeId(); auto& graphPtr = storedParent->GetGraphPtr(); @@ -380,15 +337,51 @@ class SignalLinkNode : public SignalNode } std::weak_ptr parent; - - NodeId nodeId; - Signal dep; - Group srcGroup; }; + Signal dep_; + Group srcGroup; + NodeId outputNodeId_; VirtualOutputNode linkOutput_; }; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// SignalInternals +/////////////////////////////////////////////////////////////////////////////////////////////////// +template +class SignalInternals +{ +public: + SignalInternals(const SignalInternals&) = default; + SignalInternals& operator=(const SignalInternals&) = default; + + SignalInternals(SignalInternals&&) = default; + SignalInternals& operator=(SignalInternals&&) = default; + + explicit SignalInternals(std::shared_ptr>&& nodePtr) : + nodePtr_( std::move(nodePtr) ) + { } + + auto GetNodePtr() -> std::shared_ptr>& + { return nodePtr_; } + + auto GetNodePtr() const -> const std::shared_ptr>& + { return nodePtr_; } + + NodeId GetNodeId() const + { return nodePtr_->GetNodeId(); } + + S& Value() + { return nodePtr_->Value(); } + + const S& Value() const + { return nodePtr_->Value(); } + +private: + std::shared_ptr> nodePtr_; +}; + /****************************************/ REACT_IMPL_END /***************************************/ #endif // REACT_DETAIL_GRAPH_SIGNALNODES_H_INCLUDED \ No newline at end of file diff --git a/project/msvc/CppReact.sln b/project/msvc/CppReact.sln index bd00b26a..5f987e52 100644 --- a/project/msvc/CppReact.sln +++ b/project/msvc/CppReact.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.25420.1 +# Visual Studio 15 +VisualStudioVersion = 15.0.27004.2005 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CppReact", "CppReact.vcxproj", "{5E56AAB9-4E33-4B9E-A315-E85CEDB75CF1}" EndProject @@ -31,6 +31,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Example_BasicSignals", "Exa EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Example_BasicSynchronization", "Example_BasicSynchronization.vcxproj", "{269329F8-A9E1-41AC-9C37-3A82A082A62C}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest-md", "..\..\..\googletest\googletest\msvc\2010\gtest-md.vcxproj", "{C8F6C172-56F2-4E76-B5FA-C3B423B31BE8}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest_main-md", "..\..\..\googletest\googletest\msvc\2010\gtest_main-md.vcxproj", "{3AF54C8A-10BF-4332-9147-F68ED9862033}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -119,6 +123,26 @@ Global {269329F8-A9E1-41AC-9C37-3A82A082A62C}.Release|Win32.Build.0 = Release|Win32 {269329F8-A9E1-41AC-9C37-3A82A082A62C}.Release|x64.ActiveCfg = Release|x64 {269329F8-A9E1-41AC-9C37-3A82A082A62C}.Release|x64.Build.0 = Release|x64 + {C8F6C172-56F2-4E76-B5FA-C3B423B31BE8}.Debug|Win32.ActiveCfg = Debug|Win32 + {C8F6C172-56F2-4E76-B5FA-C3B423B31BE8}.Debug|Win32.Build.0 = Debug|Win32 + {C8F6C172-56F2-4E76-B5FA-C3B423B31BE8}.Debug|x64.ActiveCfg = Debug|x64 + {C8F6C172-56F2-4E76-B5FA-C3B423B31BE8}.Debug|x64.Build.0 = Debug|x64 + {C8F6C172-56F2-4E76-B5FA-C3B423B31BE8}.Release|Win32.ActiveCfg = Release|Win32 + {C8F6C172-56F2-4E76-B5FA-C3B423B31BE8}.Release|Win32.Build.0 = Release|Win32 + {C8F6C172-56F2-4E76-B5FA-C3B423B31BE8}.Release|x64.ActiveCfg = Release|x64 + {C8F6C172-56F2-4E76-B5FA-C3B423B31BE8}.Release|x64.Build.0 = Release|x64 + {3AF54C8A-10BF-4332-9147-F68ED9862033}.Debug|Win32.ActiveCfg = Debug|Win32 + {3AF54C8A-10BF-4332-9147-F68ED9862033}.Debug|Win32.Build.0 = Debug|Win32 + {3AF54C8A-10BF-4332-9147-F68ED9862033}.Debug|Win32.Deploy.0 = Debug|Win32 + {3AF54C8A-10BF-4332-9147-F68ED9862033}.Debug|x64.ActiveCfg = Debug|x64 + {3AF54C8A-10BF-4332-9147-F68ED9862033}.Debug|x64.Build.0 = Debug|x64 + {3AF54C8A-10BF-4332-9147-F68ED9862033}.Debug|x64.Deploy.0 = Debug|x64 + {3AF54C8A-10BF-4332-9147-F68ED9862033}.Release|Win32.ActiveCfg = Release|Win32 + {3AF54C8A-10BF-4332-9147-F68ED9862033}.Release|Win32.Build.0 = Release|Win32 + {3AF54C8A-10BF-4332-9147-F68ED9862033}.Release|Win32.Deploy.0 = Release|Win32 + {3AF54C8A-10BF-4332-9147-F68ED9862033}.Release|x64.ActiveCfg = Release|x64 + {3AF54C8A-10BF-4332-9147-F68ED9862033}.Release|x64.Build.0 = Release|x64 + {3AF54C8A-10BF-4332-9147-F68ED9862033}.Release|x64.Deploy.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -134,5 +158,10 @@ Global {CC66BFA0-D609-46E0-9FD1-F9CC902410B1} = {518ACABC-E4A7-4E2D-9A04-FFA669A30DBF} {230C9137-CCD0-47E2-8F1F-2E1DD19984A1} = {518ACABC-E4A7-4E2D-9A04-FFA669A30DBF} {269329F8-A9E1-41AC-9C37-3A82A082A62C} = {518ACABC-E4A7-4E2D-9A04-FFA669A30DBF} + {C8F6C172-56F2-4E76-B5FA-C3B423B31BE8} = {3F97AA87-0A03-4428-94C1-C9B4007C2C80} + {3AF54C8A-10BF-4332-9147-F68ED9862033} = {3F97AA87-0A03-4428-94C1-C9B4007C2C80} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {C336763D-6F55-40BD-B6E1-9CAE12FF54E0} EndGlobalSection EndGlobal diff --git a/project/msvc/CppReact.vcxproj b/project/msvc/CppReact.vcxproj index 6b961f03..68b88817 100644 --- a/project/msvc/CppReact.vcxproj +++ b/project/msvc/CppReact.vcxproj @@ -1,5 +1,5 @@  - + Debug @@ -21,31 +21,32 @@ {5E56AAB9-4E33-4B9E-A315-E85CEDB75CF1} CppReact + 8.1 StaticLibrary true - v140 + v141 MultiByte StaticLibrary true - v140 + v141 MultiByte StaticLibrary false - v140 + v141 true MultiByte StaticLibrary false - v140 + v141 true MultiByte @@ -105,6 +106,7 @@ $(SolutionDir)..\..\include;%(AdditionalIncludeDirectories) true %(PreprocessorDefinitions) + stdcpp17 true @@ -143,6 +145,7 @@ $(SolutionDir)..\..\include;%(AdditionalIncludeDirectories) true %(PreprocessorDefinitions) + stdcpp17 true @@ -154,32 +157,27 @@ - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + diff --git a/project/msvc/CppReact.vcxproj.filters b/project/msvc/CppReact.vcxproj.filters index c78bde77..d87af090 100644 --- a/project/msvc/CppReact.vcxproj.filters +++ b/project/msvc/CppReact.vcxproj.filters @@ -16,88 +16,70 @@ {82fd9b9e-0b63-40f7-b245-b5eb0271b0d2} - - {c7adc39d-d19e-4fe2-b945-332515717bc8} - {11a75126-8bfd-4693-be4b-4e06ab73450c} {3f444875-ab1a-4bbd-99eb-7018c930098a} + + {45678bfc-0ce5-4e47-a365-54a72d8ecb6d} + - - Header Files\common - - - Header Files\common + + Header Files - - Header Files\common + + Header Files - - Header Files\common + + Header Files - - Header Files\common + + Header Files - - Header Files\common + + Header Files - + Header Files\detail - - Header Files\detail\graph - - - Header Files\detail\graph - - + Header Files\detail - - Header Files\detail\graph - - - Header Files\detail\graph - - - Header Files\detail\graph - - - Header Files\common + + Header Files\detail - - Header Files\common + + Header Files\detail - + Header Files\detail - - Header Files\detail\graph + + Header Files\detail - - Header Files\detail\graph + + Header Files\detail - + Header Files - - Header Files + + Header Files\detail - - Header Files + + Header Files\common - - Header Files + + Header Files\common - - Header Files + + Header Files\common - - Header Files + + Header Files\common @@ -110,5 +92,8 @@ Source Files\engine + + Source Files\detail + \ No newline at end of file diff --git a/project/msvc/CppReactBenchmark.vcxproj b/project/msvc/CppReactBenchmark.vcxproj index a57e4b20..d6cd06b4 100644 --- a/project/msvc/CppReactBenchmark.vcxproj +++ b/project/msvc/CppReactBenchmark.vcxproj @@ -1,5 +1,5 @@  - + Debug @@ -26,26 +26,26 @@ Application true - v140 + v141 MultiByte Application true - v140 + v141 MultiByte Application false - v140 + v141 true MultiByte Application false - v140 + v141 true MultiByte diff --git a/project/msvc/CppReactExample.vcxproj b/project/msvc/CppReactExample.vcxproj index 34a714e6..65945095 100644 --- a/project/msvc/CppReactExample.vcxproj +++ b/project/msvc/CppReactExample.vcxproj @@ -1,5 +1,5 @@  - + Debug @@ -27,26 +27,26 @@ Application true - v140 + v141 MultiByte Application true - v140 + v141 MultiByte Application false - v140 + v141 true MultiByte Application false - v140 + v141 true MultiByte diff --git a/project/msvc/CppReactTest.vcxproj b/project/msvc/CppReactTest.vcxproj index 5c2878a4..eccef6a3 100644 --- a/project/msvc/CppReactTest.vcxproj +++ b/project/msvc/CppReactTest.vcxproj @@ -1,5 +1,5 @@  - + Debug @@ -26,26 +26,26 @@ Application true - v140 + v141 MultiByte Application true - v140 + v141 MultiByte Application false - v140 + v141 true MultiByte Application false - v140 + v141 true MultiByte @@ -93,26 +93,19 @@ true - $(GTestDir)\msvc\gtest-md\Debug;%(AdditionalLibraryDirectories) gtestd.lib;gtest_main-mdd.lib;%(AdditionalDependencies) Console - Level3 - Disabled true $(SolutionDir)..\..\include;$(GTestDir)\include;%(AdditionalIncludeDirectories) - _VARIADIC_MAX=10;%(PreprocessorDefinitions) true 4503;%(DisableSpecificWarnings) - /bigobj %(AdditionalOptions) true - $(GTestDir)\msvc\gtest-md\Debug;%(AdditionalLibraryDirectories) - gtestd.lib;gtest_main-mdd.lib;%(AdditionalDependencies) Console @@ -141,12 +134,10 @@ Level3 - MaxSpeed true true true $(SolutionDir)..\..\include;$(GTestDir)\include;%(AdditionalIncludeDirectories) - _VARIADIC_MAX=10;%(PreprocessorDefinitions) true 4503;%(DisableSpecificWarnings) /bigobj %(AdditionalOptions) @@ -155,40 +146,31 @@ true true true - $(GTestDir)\msvc\gtest-md\Release;%(AdditionalLibraryDirectories) - gtest.lib;gtest_main-md.lib;%(AdditionalDependencies) Console false + + {c8f6c172-56f2-4e76-b5fa-c3b423b31be8} + + + {3af54c8a-10bf-4332-9147-f68ed9862033} + {5e56aab9-4e33-4b9e-a315-e85cedb75cf1} - - + + - - - - - - - - - - - - - diff --git a/project/msvc/CppReactTest.vcxproj.filters b/project/msvc/CppReactTest.vcxproj.filters index ae74e006..a6f9919a 100644 --- a/project/msvc/CppReactTest.vcxproj.filters +++ b/project/msvc/CppReactTest.vcxproj.filters @@ -15,64 +15,29 @@ - - Source Files - - - Source Files - Source Files Source Files - - Source Files - Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - \ No newline at end of file diff --git a/project/msvc/Example_BasicAlgorithms.vcxproj b/project/msvc/Example_BasicAlgorithms.vcxproj index f77233e6..f376172b 100644 --- a/project/msvc/Example_BasicAlgorithms.vcxproj +++ b/project/msvc/Example_BasicAlgorithms.vcxproj @@ -1,5 +1,5 @@  - + Debug @@ -26,26 +26,26 @@ Application true - v140 + v141 MultiByte Application true - v140 + v141 MultiByte Application false - v140 + v141 true MultiByte Application false - v140 + v141 true MultiByte diff --git a/project/msvc/Example_BasicComposition.vcxproj b/project/msvc/Example_BasicComposition.vcxproj index 43101fb2..17164ed5 100644 --- a/project/msvc/Example_BasicComposition.vcxproj +++ b/project/msvc/Example_BasicComposition.vcxproj @@ -1,5 +1,5 @@  - + Debug @@ -26,26 +26,26 @@ Application true - v140 + v141 MultiByte Application true - v140 + v141 MultiByte Application false - v140 + v141 true MultiByte Application false - v140 + v141 true MultiByte diff --git a/project/msvc/Example_BasicEvents.vcxproj b/project/msvc/Example_BasicEvents.vcxproj index 07370926..c6d6256a 100644 --- a/project/msvc/Example_BasicEvents.vcxproj +++ b/project/msvc/Example_BasicEvents.vcxproj @@ -1,5 +1,5 @@  - + Debug @@ -26,26 +26,26 @@ Application true - v140 + v141 MultiByte Application true - v140 + v141 MultiByte Application false - v140 + v141 true MultiByte Application false - v140 + v141 true MultiByte diff --git a/project/msvc/Example_BasicObservers.vcxproj b/project/msvc/Example_BasicObservers.vcxproj index 7e27da42..ff78e91c 100644 --- a/project/msvc/Example_BasicObservers.vcxproj +++ b/project/msvc/Example_BasicObservers.vcxproj @@ -1,5 +1,5 @@  - + Debug @@ -26,26 +26,26 @@ Application true - v140 + v141 MultiByte Application true - v140 + v141 MultiByte Application false - v140 + v141 true MultiByte Application false - v140 + v141 true MultiByte diff --git a/project/msvc/Example_BasicSignals.vcxproj b/project/msvc/Example_BasicSignals.vcxproj index 556b2ad0..4e8cb03d 100644 --- a/project/msvc/Example_BasicSignals.vcxproj +++ b/project/msvc/Example_BasicSignals.vcxproj @@ -1,5 +1,5 @@  - + Debug @@ -26,26 +26,26 @@ Application true - v140 + v141 MultiByte Application true - v140 + v141 MultiByte Application false - v140 + v141 true MultiByte Application false - v140 + v141 true MultiByte diff --git a/project/msvc/Example_BasicSynchronization.vcxproj b/project/msvc/Example_BasicSynchronization.vcxproj index faa0ccfb..2de78be0 100644 --- a/project/msvc/Example_BasicSynchronization.vcxproj +++ b/project/msvc/Example_BasicSynchronization.vcxproj @@ -1,5 +1,5 @@  - + Debug @@ -26,26 +26,26 @@ Application true - v140 + v141 MultiByte Application true - v140 + v141 MultiByte Application false - v140 + v141 true MultiByte Application false - v140 + v141 true MultiByte diff --git a/src/detail/graph_impl.cpp b/src/detail/graph_impl.cpp new file mode 100644 index 00000000..8dc4be9a --- /dev/null +++ b/src/detail/graph_impl.cpp @@ -0,0 +1,248 @@ +// Copyright Sebastian Jeckel 2017. +// 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 "react/detail/defs.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "react/detail/graph_impl.h" + +#include "react/common/types.h" +#include "react/common/expected.h" +#include "react/detail/graph_interface.h" + + +/***************************************/ REACT_IMPL_BEGIN /**************************************/ + +NodeId ReactGraph::RegisterNode(IReactNode* nodePtr, NodeCategory category) +{ + return nodeData_.Insert(NodeData{ nodePtr, category }); +} + +void ReactGraph::UnregisterNode(NodeId nodeId) +{ + nodeData_.Erase(nodeId); +} + +void ReactGraph::AttachNode(NodeId nodeId, NodeId parentId) +{ + auto& node = nodeData_[nodeId]; + auto& parent = nodeData_[parentId]; + + parent.successors.push_back(nodeId); + + if (node.level <= parent.level) + node.level = parent.level + 1; +} + +void ReactGraph::DetachNode(NodeId nodeId, NodeId parentId) +{ + auto& parent = nodeData_[parentId]; + auto& successors = parent.successors; + + successors.erase(std::find(successors.begin(), successors.end(), nodeId)); +} + +void ReactGraph::PushDependency(SyncPoint::Dependency dep) +{ + curDependencies_.push_back(std::move(dep)); +} + +void ReactGraph::Propagate() +{ + // Fill update queue with successors of changed inputs. + for (NodeId nodeId : changedInputs_) + { + auto& node = nodeData_[nodeId]; + auto* nodePtr = node.nodePtr; + + if (nodePtr->Update(0u) == UpdateResult::changed) + { + changedNodes_.push_back(nodePtr); + ScheduleSuccessors(node); + } + } + + // Propagate changes. + while (scheduledNodes_.FetchNext()) + { + for (NodeId nodeId : scheduledNodes_.Next()) + { + auto& node = nodeData_[nodeId]; + auto* nodePtr = node.nodePtr; + + if (node.level < node.newLevel) + { + // Re-schedule this node + node.level = node.newLevel; + RecalculateSuccessorLevels(node); + scheduledNodes_.Push(nodeId, node.level); + continue; + } + + // Special handling for link output nodes. They have no successors and they don't have to be updated. + if (node.category == NodeCategory::linkoutput) + { + node.nodePtr->CollectOutput(scheduledLinkOutputs_); + continue; + } + + if (nodePtr->Update(0u) == UpdateResult::changed) + { + changedNodes_.push_back(nodePtr); + ScheduleSuccessors(node); + } + + node.queued = false; + } + } + + if (!scheduledLinkOutputs_.empty()) + UpdateLinkNodes(); + + // Cleanup buffers in changed nodes. + for (IReactNode* nodePtr : changedNodes_) + nodePtr->Clear(); + changedNodes_.clear(); +} + +void ReactGraph::UpdateLinkNodes() +{ + for (auto& e : scheduledLinkOutputs_) + { + e.first->EnqueueTransaction(TransactionFlags::none, + [inputs = std::move(e.second)] + { + for (auto& callback : inputs) + callback(); + }); + } + + scheduledLinkOutputs_.clear(); +} + +void ReactGraph::ScheduleSuccessors(NodeData& node) +{ + for (NodeId succId : node.successors) + { + auto& succ = nodeData_[succId]; + + if (!succ.queued) + { + succ.queued = true; + scheduledNodes_.Push(succId, succ.level); + } + } +} + +void ReactGraph::RecalculateSuccessorLevels(NodeData& node) +{ + for (NodeId succId : node.successors) + { + auto& succ = nodeData_[succId]; + + if (succ.newLevel <= node.level) + succ.newLevel = node.level + 1; + } +} + +bool ReactGraph::TopoQueue::FetchNext() +{ + // Throw away previous values + nextData_.clear(); + + // Find min level of nodes in queue data + minLevel_ = (std::numeric_limits::max)(); + for (const auto& e : queueData_) + if (minLevel_ > e.second) + minLevel_ = e.second; + + // Swap entries with min level to the end + auto p = std::partition(queueData_.begin(), queueData_.end(), [t = minLevel_] (const Entry& e) { return t != e.second; }); + + // Move min level values to next data + nextData_.reserve(std::distance(p, queueData_.end())); + + for (auto it = p; it != queueData_.end(); ++it) + nextData_.push_back(it->first); + + // Truncate moved entries + queueData_.resize(std::distance(queueData_.begin(), p)); + + return !nextData_.empty(); +} + +void TransactionQueue::ProcessQueue() +{ + for (;;) + { + size_t popCount = ProcessNextBatch(); + if (count_.fetch_sub(popCount) == popCount) + return; + } +} + +size_t TransactionQueue::ProcessNextBatch() +{ + StoredTransaction curTransaction; + size_t popCount = 0; + bool canMerge = false; + bool skipPop = false; + bool isDone = false; + + // Outer loop. One transaction per iteration. + for (;;) + { + if (!skipPop) + { + if (!transactions_.try_pop(curTransaction)) + return popCount; + + canMerge = IsBitmaskSet(curTransaction.flags, TransactionFlags::allow_merging); + ++popCount; + } + else + { + skipPop = false; + } + + graph_.DoTransaction([&] + { + curTransaction.func(); + + if (canMerge) + { + // Inner loop. Mergeable transactions are merged + for (;;) + { + if (transactions_.try_pop(curTransaction)) + return; + + canMerge = IsBitmaskSet(curTransaction.flags, TransactionFlags::allow_merging); + ++popCount; + + if (!canMerge) + { + skipPop = true; + return; + } + + curTransaction.func(); + } + } + }); + } +} + +/****************************************/ REACT_IMPL_END /***************************************/ \ No newline at end of file diff --git a/src/engine/PulsecountEngine.cpp b/src/engine/PulsecountEngine.cpp index 0be62ba6..c5318fd6 100644 --- a/src/engine/PulsecountEngine.cpp +++ b/src/engine/PulsecountEngine.cpp @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2016. +// Copyright Sebastian Jeckel 2017. // 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) @@ -189,12 +189,12 @@ Turn::Turn(TurnIdT id, TransactionFlagsT flags) : /// PulsecountEngine /////////////////////////////////////////////////////////////////////////////////////////////////// -void EngineBase::OnNodeAttach(Node& node, Node& parent) +void EngineBase::AttachNode(Node& node, Node& parent) { parent.Successors.Add(node); } -void EngineBase::OnNodeDetach(Node& node, Node& parent) +void EngineBase::DetachNode(Node& node, Node& parent) { parent.Successors.Remove(node); } diff --git a/src/engine/SubtreeEngine.cpp b/src/engine/SubtreeEngine.cpp index 8584fcc2..69fb3278 100644 --- a/src/engine/SubtreeEngine.cpp +++ b/src/engine/SubtreeEngine.cpp @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2016. +// Copyright Sebastian Jeckel 2017. // 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) @@ -33,7 +33,7 @@ Turn::Turn(TurnIdT id, TransactionFlagsT flags) : /// PulsecountEngine /////////////////////////////////////////////////////////////////////////////////////////////////// -void EngineBase::OnNodeAttach(Node& node, Node& parent) +void EngineBase::AttachNode(Node& node, Node& parent) { parent.Successors.Add(node); @@ -41,7 +41,7 @@ void EngineBase::OnNodeAttach(Node& node, Node& parent) node.Level = parent.Level + 1; } -void EngineBase::OnNodeDetach(Node& node, Node& parent) +void EngineBase::DetachNode(Node& node, Node& parent) { parent.Successors.Remove(node); } @@ -230,7 +230,7 @@ void EngineBase::OnDynamicNodeAttach(Node& node, Node& parent, Turn& turn) } else { - OnNodeAttach(node, parent); + AttachNode(node, parent); invalidateSuccessors(node); @@ -245,7 +245,7 @@ void EngineBase::OnDynamicNodeDetach(Node& node, Node& parent, Turn& turn) if (isInPhase2_) applyAsyncDynamicDetach(node, parent, turn); else - OnNodeDetach(node, parent); + DetachNode(node, parent); } void EngineBase::applyAsyncDynamicAttach(Node& node, Node& parent, Turn& turn) diff --git a/src/engine/ToposortEngine.cpp b/src/engine/ToposortEngine.cpp index b8db5f67..1029775f 100644 --- a/src/engine/ToposortEngine.cpp +++ b/src/engine/ToposortEngine.cpp @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2016. +// Copyright Sebastian Jeckel 2017. // 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) @@ -30,7 +30,7 @@ ParTurn::ParTurn(TurnIdT id, TransactionFlagsT flags) : /// EngineBase /////////////////////////////////////////////////////////////////////////////////////////////////// template -void EngineBase::OnNodeAttach(TNode& node, TNode& parent) +void EngineBase::AttachNode(TNode& node, TNode& parent) { parent.Successors.Add(node); @@ -39,7 +39,7 @@ void EngineBase::OnNodeAttach(TNode& node, TNode& parent) } template -void EngineBase::OnNodeDetach(TNode& node, TNode& parent) +void EngineBase::DetachNode(TNode& node, TNode& parent) { parent.Successors.Remove(node); } @@ -85,7 +85,7 @@ void SeqEngineBase::Propagate(SeqTurn& turn) void SeqEngineBase::OnDynamicNodeAttach(SeqNode& node, SeqNode& parent, SeqTurn& turn) { - this->OnNodeAttach(node, parent); + this->AttachNode(node, parent); invalidateSuccessors(node); @@ -96,7 +96,7 @@ void SeqEngineBase::OnDynamicNodeAttach(SeqNode& node, SeqNode& parent, SeqTurn& void SeqEngineBase::OnDynamicNodeDetach(SeqNode& node, SeqNode& parent, SeqTurn& turn) { - this->OnNodeDetach(node, parent); + this->DetachNode(node, parent); } void SeqEngineBase::processChildren(SeqNode& node, SeqTurn& turn) @@ -184,7 +184,7 @@ void ParEngineBase::OnDynamicNodeDetach(ParNode& node, ParNode& parent, ParTurn& void ParEngineBase::applyDynamicAttach(ParNode& node, ParNode& parent, ParTurn& turn) { - this->OnNodeAttach(node, parent); + this->AttachNode(node, parent); invalidateSuccessors(node); @@ -195,7 +195,7 @@ void ParEngineBase::applyDynamicAttach(ParNode& node, ParNode& parent, ParTurn& void ParEngineBase::applyDynamicDetach(ParNode& node, ParNode& parent, ParTurn& turn) { - this->OnNodeDetach(node, parent); + this->DetachNode(node, parent); } void ParEngineBase::processChildren(ParNode& node, ParTurn& turn) diff --git a/src/logging/EventLog.cpp b/src/logging/EventLog.cpp deleted file mode 100644 index dcd8f627..00000000 --- a/src/logging/EventLog.cpp +++ /dev/null @@ -1,84 +0,0 @@ - -// Copyright Sebastian Jeckel 2016. -// 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 "react/logging/EventLog.h" - -/***************************************/ REACT_IMPL_BEGIN /**************************************/ - -using std::chrono::duration_cast; -using std::chrono::microseconds; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// EventLog -/////////////////////////////////////////////////////////////////////////////////////////////////// -EventLog::Entry::Entry() : - time_{ std::chrono::system_clock::now() }, - data_{ nullptr } -{ -} - -EventLog::Entry::Entry(const Entry& other) : - time_{ other.time_ }, - data_{ other.data_} -{ -} - -EventLog::Entry::Entry(IEventRecord* ptr) : - time_{ std::chrono::system_clock::now() }, - data_{ ptr } -{ -} - -void EventLog::Entry::Serialize(std::ostream& out, const TimestampT& startTime) const -{ - out << EventId() << " : " << duration_cast(Time() - startTime).count() << std::endl; - data_->Serialize(out); -} - -EventLog::Entry& EventLog::Entry::operator=(Entry& rhs) -{ - time_ = rhs.time_, - data_ = std::move(rhs.data_); - return *this; -} - -bool EventLog::Entry::Equals(const Entry& other) const -{ - if (EventId() != other.EventId()) - return false; - // Todo - return false; -} - -EventLog::EventLog() : - startTime_(std::chrono::system_clock::now()) -{ -} - -EventLog::~EventLog() -{ - Clear(); -} - -void EventLog::Print() -{ - Write(std::cout); -} - -void EventLog::Write(std::ostream& out) -{ - for (auto& e : entries_) - e.Serialize(out, startTime_); -} - -void EventLog::Clear() -{ - for (auto& e : entries_) - e.Release(); - entries_.clear(); -} - -/****************************************/ REACT_IMPL_END /***************************************/ \ No newline at end of file diff --git a/src/logging/EventRecords.cpp b/src/logging/EventRecords.cpp deleted file mode 100644 index 3145c43a..00000000 --- a/src/logging/EventRecords.cpp +++ /dev/null @@ -1,210 +0,0 @@ - -// Copyright Sebastian Jeckel 2016. -// 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 "react/logging/EventRecords.h" - -/***************************************/ REACT_IMPL_BEGIN /**************************************/ - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// NodeCreateEvent -/////////////////////////////////////////////////////////////////////////////////////////////////// -NodeCreateEvent::NodeCreateEvent(ObjectId nodeId, const char* type) : - nodeId_( nodeId ), - type_( type ) -{} - -void NodeCreateEvent::Serialize(std::ostream& out) const -{ - out << "> Node = " << nodeId_ << std::endl; - out << "> Type = " << type_ << std::endl; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// NodeDestroyEvent -/////////////////////////////////////////////////////////////////////////////////////////////////// -NodeDestroyEvent::NodeDestroyEvent(ObjectId nodeId) : - nodeId_( nodeId ) -{} - -void NodeDestroyEvent::Serialize(std::ostream& out) const -{ - out << "> Node = " << nodeId_ << std::endl; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// NodeAttachEvent -/////////////////////////////////////////////////////////////////////////////////////////////////// -NodeAttachEvent::NodeAttachEvent(ObjectId nodeId, ObjectId parentId) : - nodeId_( nodeId ), - parentId_{ parentId } -{} - -void NodeAttachEvent::Serialize(std::ostream& out) const -{ - out << "> Node = " << nodeId_ << std::endl; - out << "> Parent = " << parentId_ << std::endl; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// NodeDetachEvent -/////////////////////////////////////////////////////////////////////////////////////////////////// -NodeDetachEvent::NodeDetachEvent(ObjectId nodeId, ObjectId parentId) : - nodeId_( nodeId ), - parentId_{ parentId } -{} - -void NodeDetachEvent::Serialize(std::ostream& out) const -{ - out << "> Node = " << nodeId_ << std::endl; - out << "> Parent = " << parentId_ << std::endl; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// InputNodeAdmissionEvent -/////////////////////////////////////////////////////////////////////////////////////////////////// -InputNodeAdmissionEvent::InputNodeAdmissionEvent(ObjectId nodeId, int transactionId) : - nodeId_( nodeId ), - transactionId_( transactionId ) -{} - -void InputNodeAdmissionEvent::Serialize(std::ostream& out) const -{ - out << "> Node = " << nodeId_ << std::endl; - out << "> Transaction = " << transactionId_ << std::endl; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// NodePulseEvent -/////////////////////////////////////////////////////////////////////////////////////////////////// -NodePulseEvent::NodePulseEvent(ObjectId nodeId, int transactionId) : - nodeId_( nodeId ), - transactionId_( transactionId ) -{} - -void NodePulseEvent::Serialize(std::ostream& out) const -{ - out << "> Node = " << nodeId_ << std::endl; - out << "> Transaction = " << transactionId_ << std::endl; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// NodeIdlePulseEvent -/////////////////////////////////////////////////////////////////////////////////////////////////// -NodeIdlePulseEvent::NodeIdlePulseEvent(ObjectId nodeId, int transactionId) : - nodeId_( nodeId ), - transactionId_( transactionId ) -{} - -void NodeIdlePulseEvent::Serialize(std::ostream& out) const -{ - out << "> Node = " << nodeId_ << std::endl; - out << "> Transaction = " << transactionId_ << std::endl; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// DynamicNodeAttachEvent -/////////////////////////////////////////////////////////////////////////////////////////////////// -DynamicNodeAttachEvent::DynamicNodeAttachEvent(ObjectId nodeId, ObjectId parentId, int transactionId) : - nodeId_( nodeId ), - parentId_{ parentId }, - transactionId_( transactionId ) -{} - -void DynamicNodeAttachEvent::Serialize(std::ostream& out) const -{ - out << "> Node = " << nodeId_ << std::endl; - out << "> Parent = " << parentId_ << std::endl; - out << "> Transaction = " << transactionId_ << std::endl; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// DynamicNodeDetachEvent -/////////////////////////////////////////////////////////////////////////////////////////////////// -DynamicNodeDetachEvent::DynamicNodeDetachEvent(ObjectId nodeId, ObjectId parentId, int transactionId) : - nodeId_( nodeId ), - parentId_{ parentId }, - transactionId_( transactionId ) -{} - -void DynamicNodeDetachEvent::Serialize(std::ostream& out) const -{ - out << "> Node = " << nodeId_ << std::endl; - out << "> Parent = " << parentId_ << std::endl; - out << "> Transaction = " << transactionId_ << std::endl; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// NodeEvaluateBeginEvent -/////////////////////////////////////////////////////////////////////////////////////////////////// -NodeEvaluateBeginEvent::NodeEvaluateBeginEvent(ObjectId nodeId, int transactionId) : - nodeId_( nodeId ), - transactionId_( transactionId ), - threadId_( std::this_thread::get_id() ) -{} - -void NodeEvaluateBeginEvent::Serialize(std::ostream& out) const -{ - out << "> Node = " << nodeId_ << std::endl; - out << "> Transaction = " << transactionId_ << std::endl; - out << "> Thread = " << threadId_ << std::endl; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// NodeEvaluateEndEvent -/////////////////////////////////////////////////////////////////////////////////////////////////// -NodeEvaluateEndEvent::NodeEvaluateEndEvent(ObjectId nodeId, int transactionId) : - nodeId_( nodeId ), - transactionId_( transactionId ), - threadId_{ std::this_thread::get_id() } -{} - -void NodeEvaluateEndEvent::Serialize(std::ostream& out) const -{ - out << "> Node = " << nodeId_ << std::endl; - out << "> Transaction = " << transactionId_ << std::endl; - out << "> Thread = " << threadId_ << std::endl; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// TransactionBeginEvent -/////////////////////////////////////////////////////////////////////////////////////////////////// -TransactionBeginEvent::TransactionBeginEvent(int transactionId) : - transactionId_( transactionId ) -{} - -void TransactionBeginEvent::Serialize(std::ostream& out) const -{ - out << "> Transaction = " << transactionId_ << std::endl; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// TransactionEndEvent -/////////////////////////////////////////////////////////////////////////////////////////////////// -TransactionEndEvent::TransactionEndEvent(int transactionId) : - transactionId_( transactionId ) -{} - -void TransactionEndEvent::Serialize(std::ostream& out) const -{ - out << "> Transaction = " << transactionId_ << std::endl; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// UserBreakpointEvent -/////////////////////////////////////////////////////////////////////////////////////////////////// -UserBreakpointEvent::UserBreakpointEvent(const char* name) : - name_( name ) -{} - -void UserBreakpointEvent::Serialize(std::ostream& out) const -{ - out << "> Name = " << name_ << std::endl; -} - -/****************************************/ REACT_IMPL_END /***************************************/ \ No newline at end of file diff --git a/tests/src/EventStreamTest.cpp b/tests/src/EventStreamTest.cpp deleted file mode 100644 index 6801c5e9..00000000 --- a/tests/src/EventStreamTest.cpp +++ /dev/null @@ -1,29 +0,0 @@ - -// Copyright Sebastian Jeckel 2016. -// 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 "EventStreamTest.h" -#include "TestUtil.h" - -#include "react/engine/PulsecountEngine.h" -#include "react/engine/ToposortEngine.h" -#include "react/engine/SubtreeEngine.h" - -/////////////////////////////////////////////////////////////////////////////////////////////////// -namespace { - -using namespace react; - -using P1 = DomainParams; -using P2 = DomainParams; -using P3 = DomainParams; -using P4 = DomainParams; - -INSTANTIATE_TYPED_TEST_CASE_P(SeqToposort, EventStreamTest, P1); -INSTANTIATE_TYPED_TEST_CASE_P(ParToposort, EventStreamTest, P2); -INSTANTIATE_TYPED_TEST_CASE_P(Pulsecount, EventStreamTest, P3); -INSTANTIATE_TYPED_TEST_CASE_P(Subtree, EventStreamTest, P4); - -} // ~namespace \ No newline at end of file diff --git a/tests/src/EventStreamTest.h b/tests/src/EventStreamTest.h index e33653a0..db12a8ea 100644 --- a/tests/src/EventStreamTest.h +++ b/tests/src/EventStreamTest.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2016. +// Copyright Sebastian Jeckel 2017. // 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) diff --git a/tests/src/EventStreamTestQ.cpp b/tests/src/EventStreamTestQ.cpp index d61330d1..26d07507 100644 --- a/tests/src/EventStreamTestQ.cpp +++ b/tests/src/EventStreamTestQ.cpp @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2016. +// Copyright Sebastian Jeckel 2017. // 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) diff --git a/tests/src/MoveTest.cpp b/tests/src/MoveTest.cpp index c5963745..6054092a 100644 --- a/tests/src/MoveTest.cpp +++ b/tests/src/MoveTest.cpp @@ -1,21 +1,12 @@ -// Copyright Sebastian Jeckel 2016. +// Copyright Sebastian Jeckel 2017. // 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 "MoveTest.h" -#include "TestUtil.h" - -#include "react/engine/ToposortEngine.h" /////////////////////////////////////////////////////////////////////////////////////////////////// namespace { -using namespace react; - -using P1 = DomainParams; - -INSTANTIATE_TYPED_TEST_CASE_P(SeqToposort, MoveTest, P1); } // ~namespace \ No newline at end of file diff --git a/tests/src/MoveTest.h b/tests/src/MoveTest.h index 41eb5810..0804423a 100644 --- a/tests/src/MoveTest.h +++ b/tests/src/MoveTest.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2016. +// Copyright Sebastian Jeckel 2017. // 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) diff --git a/tests/src/ObserverTest.cpp b/tests/src/ObserverTest.cpp index ae331812..6054092a 100644 --- a/tests/src/ObserverTest.cpp +++ b/tests/src/ObserverTest.cpp @@ -1,29 +1,12 @@ -// Copyright Sebastian Jeckel 2016. +// Copyright Sebastian Jeckel 2017. // 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 "ObserverTest.h" -#include "TestUtil.h" - -#include "react/engine/PulsecountEngine.h" -#include "react/engine/ToposortEngine.h" -#include "react/engine/SubtreeEngine.h" /////////////////////////////////////////////////////////////////////////////////////////////////// namespace { -using namespace react; - -using P1 = DomainParams; -using P2 = DomainParams; -using P3 = DomainParams; -using P4 = DomainParams; - -INSTANTIATE_TYPED_TEST_CASE_P(SeqToposort, ObserverTest, P1); -INSTANTIATE_TYPED_TEST_CASE_P(ParToposort, ObserverTest, P2); -INSTANTIATE_TYPED_TEST_CASE_P(Pulsecount, ObserverTest, P3); -INSTANTIATE_TYPED_TEST_CASE_P(Subtree, ObserverTest, P4); } // ~namespace \ No newline at end of file diff --git a/tests/src/ObserverTest.h b/tests/src/ObserverTest.h index af5ac834..559c0686 100644 --- a/tests/src/ObserverTest.h +++ b/tests/src/ObserverTest.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2016. +// Copyright Sebastian Jeckel 2017. // 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) diff --git a/tests/src/ObserverTestQ.cpp b/tests/src/ObserverTestQ.cpp index 1e36c088..4dfe55f6 100644 --- a/tests/src/ObserverTestQ.cpp +++ b/tests/src/ObserverTestQ.cpp @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2016. +// Copyright Sebastian Jeckel 2017. // 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) diff --git a/tests/src/OperationsTest.cpp b/tests/src/OperationsTest.cpp index cc3b576e..6054092a 100644 --- a/tests/src/OperationsTest.cpp +++ b/tests/src/OperationsTest.cpp @@ -1,29 +1,12 @@ -// Copyright Sebastian Jeckel 2016. +// Copyright Sebastian Jeckel 2017. // 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 "OperationsTest.h" -#include "TestUtil.h" - -#include "react/engine/PulsecountEngine.h" -#include "react/engine/ToposortEngine.h" -#include "react/engine/SubtreeEngine.h" /////////////////////////////////////////////////////////////////////////////////////////////////// namespace { -using namespace react; - -using P1 = DomainParams; -using P2 = DomainParams; -using P3 = DomainParams; -using P4 = DomainParams; - -INSTANTIATE_TYPED_TEST_CASE_P(SeqToposort, OperationsTest, P1); -INSTANTIATE_TYPED_TEST_CASE_P(ParToposort, OperationsTest, P2); -INSTANTIATE_TYPED_TEST_CASE_P(Pulsecount, OperationsTest, P3); -INSTANTIATE_TYPED_TEST_CASE_P(Subtree, OperationsTest, P4); } // ~namespace \ No newline at end of file diff --git a/tests/src/OperationsTest.h b/tests/src/OperationsTest.h index 1af27694..c7fb6d3f 100644 --- a/tests/src/OperationsTest.h +++ b/tests/src/OperationsTest.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2016. +// Copyright Sebastian Jeckel 2017. // 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) diff --git a/tests/src/OperationsTestQ.cpp b/tests/src/OperationsTestQ.cpp index 83e8a7ab..576c0752 100644 --- a/tests/src/OperationsTestQ.cpp +++ b/tests/src/OperationsTestQ.cpp @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2016. +// Copyright Sebastian Jeckel 2017. // 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) diff --git a/tests/src/ParallelizationTest.cpp b/tests/src/ParallelizationTest.cpp index 9ef6d156..6054092a 100644 --- a/tests/src/ParallelizationTest.cpp +++ b/tests/src/ParallelizationTest.cpp @@ -1,29 +1,12 @@ -// Copyright Sebastian Jeckel 2016. +// Copyright Sebastian Jeckel 2017. // 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 "ParallelizationTest.h" -#include "TestUtil.h" - -#include "react/engine/PulsecountEngine.h" -#include "react/engine/ToposortEngine.h" -#include "react/engine/SubtreeEngine.h" /////////////////////////////////////////////////////////////////////////////////////////////////// namespace { -using namespace react; - -using P1 = DomainParams; -using P2 = DomainParams; -using P3 = DomainParams; -using P4 = DomainParams; - -INSTANTIATE_TYPED_TEST_CASE_P(SeqToposortQ, ParallelizationTest, P1); -INSTANTIATE_TYPED_TEST_CASE_P(ParToposortQ, ParallelizationTest, P2); -INSTANTIATE_TYPED_TEST_CASE_P(PulsecountQ, ParallelizationTest, P3); -INSTANTIATE_TYPED_TEST_CASE_P(SubtreeQ, ParallelizationTest, P4); } // ~namespace \ No newline at end of file diff --git a/tests/src/ParallelizationTest.h b/tests/src/ParallelizationTest.h index 43a99f05..145c730c 100644 --- a/tests/src/ParallelizationTest.h +++ b/tests/src/ParallelizationTest.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2016. +// Copyright Sebastian Jeckel 2017. // 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) diff --git a/tests/src/SignalTest.cpp b/tests/src/SignalTest.cpp index 44a68828..a34b7f98 100644 --- a/tests/src/SignalTest.cpp +++ b/tests/src/SignalTest.cpp @@ -1,29 +1,11 @@ -// Copyright Sebastian Jeckel 2016. +// Copyright Sebastian Jeckel 2017. // 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 "SignalTest.h" -#include "TestUtil.h" - -#include "react/engine/PulsecountEngine.h" -#include "react/engine/ToposortEngine.h" -#include "react/engine/SubtreeEngine.h" /////////////////////////////////////////////////////////////////////////////////////////////////// namespace { -using namespace react; - -using P1 = DomainParams; -using P2 = DomainParams; -using P3 = DomainParams; -using P4 = DomainParams; - -INSTANTIATE_TYPED_TEST_CASE_P(SeqToposort, SignalTest, P1); -INSTANTIATE_TYPED_TEST_CASE_P(ParToposort, SignalTest, P2); -INSTANTIATE_TYPED_TEST_CASE_P(Pulsecount, SignalTest, P3); -INSTANTIATE_TYPED_TEST_CASE_P(Subtree, SignalTest, P4); - } // ~namespace \ No newline at end of file diff --git a/tests/src/SignalTest.h b/tests/src/SignalTest.h index b20eabe8..69ae81de 100644 --- a/tests/src/SignalTest.h +++ b/tests/src/SignalTest.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2016. +// Copyright Sebastian Jeckel 2017. // 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) diff --git a/tests/src/SignalTestQ.cpp b/tests/src/SignalTestQ.cpp index b6bacde1..d91875c7 100644 --- a/tests/src/SignalTestQ.cpp +++ b/tests/src/SignalTestQ.cpp @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2016. +// Copyright Sebastian Jeckel 2017. // 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) diff --git a/tests/src/TestUtil.h b/tests/src/TestUtil.h index a6cc5306..0d7b9cb6 100644 --- a/tests/src/TestUtil.h +++ b/tests/src/TestUtil.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2016. +// Copyright Sebastian Jeckel 2017. // 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) diff --git a/tests/src/TransactionTest.cpp b/tests/src/TransactionTest.cpp index 487f7f5b..6054092a 100644 --- a/tests/src/TransactionTest.cpp +++ b/tests/src/TransactionTest.cpp @@ -1,29 +1,12 @@ -// Copyright Sebastian Jeckel 2016. +// Copyright Sebastian Jeckel 2017. // 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 "TransactionTest.h" -#include "TestUtil.h" - -#include "react/engine/PulsecountEngine.h" -#include "react/engine/ToposortEngine.h" -#include "react/engine/SubtreeEngine.h" /////////////////////////////////////////////////////////////////////////////////////////////////// namespace { -using namespace react; - -using P1 = DomainParams; -using P2 = DomainParams; -using P3 = DomainParams; -using P4 = DomainParams; - -INSTANTIATE_TYPED_TEST_CASE_P(SeqToposort, TransactionTest, P1); -INSTANTIATE_TYPED_TEST_CASE_P(ParToposort, TransactionTest, P2); -INSTANTIATE_TYPED_TEST_CASE_P(Pulsecount, TransactionTest, P3); -INSTANTIATE_TYPED_TEST_CASE_P(Subtree, TransactionTest, P4); } // ~namespace \ No newline at end of file diff --git a/tests/src/TransactionTest.h b/tests/src/TransactionTest.h index a332de90..0501a81c 100644 --- a/tests/src/TransactionTest.h +++ b/tests/src/TransactionTest.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2016. +// Copyright Sebastian Jeckel 2017. // 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) diff --git a/tests/src/common_tests.cpp b/tests/src/common_tests.cpp new file mode 100644 index 00000000..0bd5b6dc --- /dev/null +++ b/tests/src/common_tests.cpp @@ -0,0 +1,132 @@ + +// Copyright Sebastian Jeckel 2017. +// 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 "gtest/gtest.h" + +#include "react/common/syncpoint.h" + +#include +#include +#include + +using namespace react; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +TEST(SyncPointTest, SingleWait) +{ + SyncPoint sp; + + SyncPoint::Dependency dep(sp); + + int output = 0; + + std::thread t1([storedDep = std::move(dep), &output] () + { + std::this_thread::sleep_for(std::chrono::seconds(1)); + output = 1; + }); + + + sp.Wait(); + + EXPECT_EQ(1, output); + + t1.join(); +} + +TEST(SyncPointTest, MultiWait) +{ + SyncPoint sp; + + SyncPoint::Dependency dep1(sp); + SyncPoint::Dependency dep2(sp); + SyncPoint::Dependency dep3(sp); + + int output1 = 0; + int output2 = 0; + int output3 = 0; + + std::thread t1([storedDep = std::move(dep1), &output1] () + { + std::this_thread::sleep_for(std::chrono::seconds(1)); + output1 = 1; + }); + + std::thread t2([storedDep = std::move(dep2), &output2] () + { + std::this_thread::sleep_for(std::chrono::seconds(1)); + output2 = 2; + }); + + std::thread t3([storedDep = std::move(dep3), &output3] () + { + std::this_thread::sleep_for(std::chrono::seconds(1)); + output3 = 3; + }); + + + sp.Wait(); + + EXPECT_EQ(1, output1); + EXPECT_EQ(2, output2); + EXPECT_EQ(3, output3); + + t1.join(); + t2.join(); + t3.join(); +} + +TEST(SyncPointTest, MultiWaitFor) +{ + SyncPoint sp; + + SyncPoint::Dependency dep1(sp); + SyncPoint::Dependency dep2(sp); + SyncPoint::Dependency dep3(sp); + + int output1 = 0; + int output2 = 0; + int output3 = 0; + + std::thread t1([storedDep = std::move(dep1), &output1] () + { + std::this_thread::sleep_for(std::chrono::seconds(3)); + output1 = 1; + }); + + std::thread t2([storedDep = std::move(dep2), &output2] () + { + std::this_thread::sleep_for(std::chrono::seconds(3)); + output2 = 2; + }); + + std::thread t3([storedDep = std::move(dep3), &output3] () + { + std::this_thread::sleep_for(std::chrono::seconds(3)); + output3 = 3; + }); + + + bool done = sp.WaitFor(std::chrono::milliseconds(1)); + + EXPECT_FALSE(done); + + EXPECT_EQ(0, output1); + EXPECT_EQ(0, output2); + EXPECT_EQ(0, output3); + + done = sp.WaitFor(std::chrono::seconds(10)); + + EXPECT_TRUE(done); + + EXPECT_EQ(1, output1); + EXPECT_EQ(2, output2); + EXPECT_EQ(3, output3); + + t1.join(); + t2.join(); + t3.join(); +} \ No newline at end of file diff --git a/tests/src/event_tests.cpp b/tests/src/event_tests.cpp new file mode 100644 index 00000000..4204a466 --- /dev/null +++ b/tests/src/event_tests.cpp @@ -0,0 +1,219 @@ + +// Copyright Sebastian Jeckel 2017. +// 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 "gtest/gtest.h" + +#include "react/event.h" +#include "react/observer.h" + +#include +#include + +using namespace react; + +TEST(EventTest, Construction) +{ + Group g; + + // Event source + { + EventSource t1( g ); + EventSource t2( t1 ); + EventSource t3( std::move(t1) ); + + EventSource ref1( t2 ); + Event ref2( t3 ); + + EXPECT_TRUE(ref1 == ref2); + } + + // Event slot + { + EventSlot t1( g ); + EventSlot t2( t1 ); + EventSlot t3( std::move(t1) ); + + EventSlot ref1( t2 ); + Event ref2( t3 ); + + EXPECT_TRUE(ref1 == ref2); + } + + // Event link + { + EventSlot s1( g ); + + EventLink t1( g, s1 ); + EventLink t2( t1 ); + EventLink t3( std::move(t1) ); + + EventLink ref1( t2 ); + Event ref2( t3 ); + + EXPECT_TRUE(ref1 == ref2); + } +} + +TEST(EventTest, BasicOutput) +{ + Group g; + + EventSource evt( g ); + + int output = 0; + + Observer obs([&] (const auto& events) + { + for (int e : events) + output += e; + }, evt); + + EXPECT_EQ(0, output); + + evt.Emit(1); + EXPECT_EQ(1, output); + + evt.Emit(2); + EXPECT_EQ(3, output); +} + +TEST(EventTest, EventSlots) +{ + Group g; + + EventSource evt1( g ); + EventSource evt2( g ); + + EventSlot slot( g ); + + int output = 0; + int turns = 0; + + Observer obs([&] (const auto& events) + { + ++turns; + + for (int e : events) + output += e; + }, slot); + + EXPECT_EQ(0, output); + EXPECT_EQ(0, turns); + + slot.Add(evt1); + slot.Add(evt2); + + evt1.Emit(5); + evt2.Emit(2); + + EXPECT_EQ(7, output); + EXPECT_EQ(2, turns); + + output = 0; + + slot.Remove(evt1); + + evt1.Emit(5); + evt2.Emit(2); + + EXPECT_EQ(2, output); + EXPECT_EQ(3, turns); + + output = 0; + + slot.Remove(evt2); + + evt1.Emit(5); + evt2.Emit(2); + + EXPECT_EQ(0, output); + EXPECT_EQ(3, turns); + + output = 0; + + slot.Add(evt1); + slot.Add(evt1); + + evt1.Emit(5); + evt2.Emit(2); + + EXPECT_EQ(5, output); + EXPECT_EQ(4, turns); +} + +TEST(EventTest, EventTransactions) +{ + Group g; + + EventSource evt( g ); + + int output = 0; + int turns = 0; + + Observer obs([&] (const auto& events) + { + ++turns; + for (int e : events) + output += e; + }, evt); + + EXPECT_EQ(0, output); + + g.DoTransaction([&] + { + evt.Emit(1); + evt.Emit(1); + evt.Emit(1); + evt.Emit(1); + }); + + EXPECT_EQ(4, output); + EXPECT_EQ(1, turns); +} + +TEST(EventTest, ExplicitEventLinks) +{ + Group g1; + Group g2; + Group g3; + + EventSource evt1( g1 ); + EventSource evt2( g2 ); + EventSource evt3( g3 ); + + EventSlot slot( g1 ); + + // Same group + slot.Add(evt1); + + // Explicit link + EventLink lnk2( g1, evt2 ); + slot.Add(lnk2); + + // Implicit link + slot.Add(evt3); + + int output = 0; + int turns = 0; + + EXPECT_EQ(0, output); + + Observer obs([&] (const auto& events) + { + ++turns; + for (int e : events) + output += e; + }, slot); + + evt1.Emit(1); + evt2.Emit(1); + evt3.Emit(1); + + std::this_thread::sleep_for(std::chrono::seconds(1)); + + EXPECT_EQ(3, output); + EXPECT_EQ(3, turns); +} \ No newline at end of file From 63488198260b1f9c75ff8c883f93fe843459a7a6 Mon Sep 17 00:00:00 2001 From: schlangster Date: Tue, 24 Oct 2017 22:33:52 +0200 Subject: [PATCH 53/75] Renamed Signal to State. General progress. --- include/react/API.h | 46 +-- include/react/Algorithm.h | 78 +++--- include/react/Event.h | 42 +-- include/react/Observer.h | 61 +--- include/react/common/slotmap.h | 2 +- include/react/common/syncpoint.h | 103 ++++--- include/react/common/utility.h | 28 ++ include/react/detail/algorithm_nodes.h | 54 ++-- include/react/detail/event_nodes.h | 80 +++--- include/react/detail/graph_impl.h | 37 ++- include/react/detail/observer_nodes.h | 66 ++++- .../detail/{signal_nodes.h => state_nodes.h} | 121 ++++---- include/react/{Signal.h => state.h} | 162 +++++------ project/msvc/CppReact.vcxproj | 6 +- project/msvc/CppReact.vcxproj.filters | 12 +- project/msvc/CppReactTest.vcxproj | 4 +- project/msvc/CppReactTest.vcxproj.filters | 10 +- src/detail/graph_impl.cpp | 49 +++- tests/src/SignalTest.cpp | 11 - tests/src/TransactionTest.cpp | 12 - tests/src/common_tests.cpp | 31 ++- tests/src/event_tests.cpp | 6 +- tests/src/state_tests.cpp | 262 ++++++++++++++++++ tests/src/transaction_tests.cpp | 220 +++++++++++++++ 24 files changed, 1031 insertions(+), 472 deletions(-) rename include/react/detail/{signal_nodes.h => state_nodes.h} (75%) rename include/react/{Signal.h => state.h} (51%) delete mode 100644 tests/src/SignalTest.cpp delete mode 100644 tests/src/TransactionTest.cpp create mode 100644 tests/src/state_tests.cpp create mode 100644 tests/src/transaction_tests.cpp diff --git a/include/react/API.h b/include/react/API.h index 3e20d5bb..89ace35c 100644 --- a/include/react/API.h +++ b/include/react/API.h @@ -37,23 +37,23 @@ REACT_DEFINE_BITMASK_OPERATORS(TransactionFlags) /// API types /////////////////////////////////////////////////////////////////////////////////////////////////// -// Groups +// Group class Group; -// Signals +// State template -class Signal; +class State; template -class VarSignal; +class StateVar; template -class SignalSlot; +class StateSlot; template -class SignalLink; +class StateLink; -// Events +// Event enum class Token; template @@ -65,39 +65,9 @@ class EventSource; template class EventSlot; -// Observers +// Observer class Observer; -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Traits -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -struct IsSignal { static const bool value = false; }; - -template -struct IsSignal> { static const bool value = true; }; - -template -struct IsSignal> { static const bool value = true; }; - -template -struct IsEvent { static const bool value = false; }; - -template -struct IsEvent> { static const bool value = true; }; - -template -struct IsEvent> { static const bool value = true; }; - -template -struct AsNonInputNode { using type = T; }; - -template -struct AsNonInputNode> { using type = Signal; }; - -template -struct AsNonInputNode> { using type = Event; }; - /******************************************/ REACT_END /******************************************/ #endif // REACT_TYPETRAITS_H_INCLUDED \ No newline at end of file diff --git a/include/react/Algorithm.h b/include/react/Algorithm.h index e149b491..9c1b2023 100644 --- a/include/react/Algorithm.h +++ b/include/react/Algorithm.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2016. +// Copyright Sebastian Jeckel 2017. // 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) @@ -18,52 +18,52 @@ #include "react/API.h" #include "react/detail/algorithm_nodes.h" +#include "react/state.h" #include "react/event.h" -#include "react/signal.h" /*****************************************/ REACT_BEGIN /*****************************************/ /////////////////////////////////////////////////////////////////////////////////////////////////// -/// Hold the most recent event in a signal +/// Hold the most recent event in a state /////////////////////////////////////////////////////////////////////////////////////////////////// template -auto Hold(const Group& group, T&& initialValue, const Event& evnt) -> Signal +auto Hold(const Group& group, T&& initialValue, const Event& evnt) -> State { using REACT_IMPL::HoldNode; using REACT_IMPL::SameGroupOrLink; using REACT_IMPL::CreateWrappedNode; - return CreateWrappedNode, HoldNode>( + return CreateWrappedNode, HoldNode>( group, std::forward(initialValue), SameGroupOrLink(group, evnt)); } template -auto Hold(T&& initialValue, const Event& evnt) -> Signal +auto Hold(T&& initialValue, const Event& evnt) -> State { return Hold(evnt.GetGroup(), std::forward(initialValue), evnt); } /////////////////////////////////////////////////////////////////////////////////////////////////// -/// Emits value changes of target signal. +/// Emits value changes of target state. /////////////////////////////////////////////////////////////////////////////////////////////////// template -auto Monitor(const Group& group, const Signal& signal) -> Event +auto Monitor(const Group& group, const State& state) -> Event { using REACT_IMPL::MonitorNode; using REACT_IMPL::SameGroupOrLink; using REACT_IMPL::CreateWrappedNode; return CreateWrappedNode, MonitorNode>( - group, SameGroupOrLink(group, signal)); + group, SameGroupOrLink(group, state)); } template -auto Monitor(const Signal& signal) -> Event - { return Monitor(signal.GetGroup(), signal); } +auto Monitor(const State& state) -> Event + { return Monitor(state.GetGroup(), state); } /////////////////////////////////////////////////////////////////////////////////////////////////// -/// Iterate - Iteratively combines signal value with values from event stream (aka Fold) +/// Iterate - Iteratively combines state value with values from event stream (aka Fold) /////////////////////////////////////////////////////////////////////////////////////////////////// template -auto Iterate(const Group& group, T&& initialValue, F&& func, const Event& evnt) -> Signal +auto Iterate(const Group& group, T&& initialValue, F&& func, const Event& evnt) -> State { using REACT_IMPL::IterateNode; using REACT_IMPL::IsCallableWith; @@ -72,12 +72,12 @@ auto Iterate(const Group& group, T&& initialValue, F&& func, const Event& evn using FuncType = typename std::decay::type; - return CreateWrappedNode, IterateNode>( + return CreateWrappedNode, IterateNode>( group, std::forward(initialValue), std::forward(func), SameGroupOrLink(group, evnt)); } template -auto IterateByRef(const Group& group, T&& initialValue, F&& func, const Event& evnt) -> Signal +auto IterateByRef(const Group& group, T&& initialValue, F&& func, const Event& evnt) -> State { using REACT_IMPL::IterateByRefNode; using REACT_IMPL::IsCallableWith; @@ -86,23 +86,23 @@ auto IterateByRef(const Group& group, T&& initialValue, F&& func, const Event using FuncType = typename std::decay::type; - return CreateWrappedNode, IterateByRefNode>( + return CreateWrappedNode, IterateByRefNode>( group, std::forward(initialValue), std::forward(func), SameGroupOrLink(group, evnt)); } template -auto Iterate(T&& initialValue, F&& func, const Event& evnt) -> Signal +auto Iterate(T&& initialValue, F&& func, const Event& evnt) -> State { return Iterate(evnt.GetGroup(), std::forward(initialValue), std::forward(func), evnt); } template -auto IterateByRef(T&& initialValue, F&& func, const Event& evnt) -> Signal +auto IterateByRef(T&& initialValue, F&& func, const Event& evnt) -> State { return IterateByRef(evnt.GetGroup(), std::forward(initialValue), std::forward(func), evnt); } /////////////////////////////////////////////////////////////////////////////////////////////////// /// Iterate - Synced /////////////////////////////////////////////////////////////////////////////////////////////////// template -auto Iterate(const Group& group, T&& initialValue, F&& func, const Event& evnt, const Signal& ... signals) -> Signal +auto Iterate(const Group& group, T&& initialValue, F&& func, const Event& evnt, const State& ... states) -> State { using REACT_IMPL::SyncedIterateNode; using REACT_IMPL::IsCallableWith; @@ -111,12 +111,12 @@ auto Iterate(const Group& group, T&& initialValue, F&& func, const Event& evn using FuncType = typename std::decay::type; - return CreateWrappedNode, SyncedIterateNode>( - group, std::forward(initialValue), std::forward(func), SameGroupOrLink(group, evnt), SameGroupOrLink(group, signals) ...); + return CreateWrappedNode, SyncedIterateNode>( + group, std::forward(initialValue), std::forward(func), SameGroupOrLink(group, evnt), SameGroupOrLink(group, states) ...); } template -auto IterateByRef(const Group& group, T&& initialValue, F&& func, const Event& evnt, const Signal& ... signals) -> Signal +auto IterateByRef(const Group& group, T&& initialValue, F&& func, const Event& evnt, const State& ... states) -> State { using REACT_IMPL::SyncedIterateByRefNode; using REACT_IMPL::IsCallableWith; @@ -125,53 +125,53 @@ auto IterateByRef(const Group& group, T&& initialValue, F&& func, const Event using FuncType = typename std::decay::type; - return CreateWrappedNode, SyncedIterateByRefNode>( - group, std::forward(initialValue), std::forward(func), SameGroupOrLink(group, evnt), SameGroupOrLink(group, signals) ...); + return CreateWrappedNode, SyncedIterateByRefNode>( + group, std::forward(initialValue), std::forward(func), SameGroupOrLink(group, evnt), SameGroupOrLink(group, states) ...); } template -auto Iterate(T&& initialValue, F&& func, const Event& evnt, const Signal& ... signals) -> Signal - { return Iterate(evnt.GetGroup(), std::forward(initialValue), std::forward(func), evnt, signals ...); } +auto Iterate(T&& initialValue, F&& func, const Event& evnt, const State& ... states) -> State + { return Iterate(evnt.GetGroup(), std::forward(initialValue), std::forward(func), evnt, states ...); } template -auto IterateByRef(T&& initialValue, F&& func, const Event& evnt, const Signal& ... signals) -> Signal - { return IterateByRef(evnt.GetGroup(), std::forward(initialValue), std::forward(func), evnt, signals ...); } +auto IterateByRef(T&& initialValue, F&& func, const Event& evnt, const State& ... states) -> State + { return IterateByRef(evnt.GetGroup(), std::forward(initialValue), std::forward(func), evnt, states ...); } /////////////////////////////////////////////////////////////////////////////////////////////////// -/// Snapshot - Sets signal value to value of other signal when event is received +/// Snapshot - Sets state value to value of other state when event is received /////////////////////////////////////////////////////////////////////////////////////////////////// template -auto Snapshot(const Group& group, const Signal& signal, const Event& evnt) -> Signal +auto Snapshot(const Group& group, const State& state, const Event& evnt) -> State { using REACT_IMPL::SnapshotNode; using REACT_IMPL::SameGroupOrLink; using REACT_IMPL::CreateWrappedNode; - return CreateWrappedNode, SnapshotNode>( - group, SameGroupOrLink(group, signal), SameGroupOrLink(group, evnt)); + return CreateWrappedNode, SnapshotNode>( + group, SameGroupOrLink(group, state), SameGroupOrLink(group, evnt)); } template -auto Snapshot(const Signal& signal, const Event& evnt) -> Signal - { return Snapshot(signal.GetGroup(), signal, evnt); } +auto Snapshot(const State& state, const Event& evnt) -> State + { return Snapshot(state.GetGroup(), state, evnt); } /////////////////////////////////////////////////////////////////////////////////////////////////// -/// Pulse - Emits value of target signal when event is received +/// Pulse - Emits value of target state when event is received /////////////////////////////////////////////////////////////////////////////////////////////////// template -auto Pulse(const Group& group, const Signal& signal, const Event& evnt) -> Event +auto Pulse(const Group& group, const State& state, const Event& evnt) -> Event { using REACT_IMPL::PulseNode; using REACT_IMPL::SameGroupOrLink; using REACT_IMPL::CreateWrappedNode; return CreateWrappedNode, PulseNode>( - group, SameGroupOrLink(group, signal), SameGroupOrLink(group, evnt)); + group, SameGroupOrLink(group, state), SameGroupOrLink(group, evnt)); } template -auto Pulse(const Signal& signal, const Event& evnt) -> Event - { return Pulse(signal.GetGroup(), signal, evnt); } +auto Pulse(const State& state, const Event& evnt) -> Event + { return Pulse(state.GetGroup(), state, evnt); } /******************************************/ REACT_END /******************************************/ diff --git a/include/react/Event.h b/include/react/Event.h index ff4a0a17..903d3dc6 100644 --- a/include/react/Event.h +++ b/include/react/Event.h @@ -51,14 +51,14 @@ class Event : protected REACT_IMPL::EventInternals // Construct with explicit group template - Event(const Group& group, F&& func, const Event& dep, const Signal& ... signals) : - Event::Event( CreateSyncedProcessingNode(group, std::forward(func), dep, signals ...) ) + Event(const Group& group, F&& func, const Event& dep, const State& ... states) : + Event::Event( CreateSyncedProcessingNode(group, std::forward(func), dep, states ...) ) { } // Construct with implicit group template - Event(F&& func, const Event& dep, const Signal& ... signals) : - Event::Event( CreateSyncedProcessingNode(dep.GetGroup(), std::forward(func), dep, signals ...) ) + Event(F&& func, const Event& dep, const State& ... states) : + Event::Event( CreateSyncedProcessingNode(dep.GetGroup(), std::forward(func), dep, states ...) ) { } auto Tokenize() const -> decltype(auto) @@ -84,7 +84,7 @@ class Event : protected REACT_IMPL::EventInternals protected: // Private node ctor - explicit Event(std::shared_ptr>&& nodePtr) : + explicit Event(std::shared_ptr>&& nodePtr) : Event::EventInternals( std::move(nodePtr) ) { } @@ -99,7 +99,7 @@ class Event : protected REACT_IMPL::EventInternals } template - auto CreateSyncedProcessingNode(const Group& group, F&& func, const Event& dep, const Signal& ... syncs) -> decltype(auto) + auto CreateSyncedProcessingNode(const Group& group, F&& func, const Event& dep, const State& ... syncs) -> decltype(auto) { using REACT_IMPL::SyncedEventProcessingNode; using REACT_IMPL::SameGroupOrLink; @@ -166,7 +166,7 @@ class EventSource : public Event NodeId nodeId = castedPtr->GetNodeId(); auto& graphPtr = GetInternals(this->GetGroup()).GetGraphPtr(); - graphPtr->AddInput(nodeId, [castedPtr, &value] { castedPtr->EmitValue(std::forward(value)); }); + graphPtr->PushInput(nodeId, [castedPtr, &value] { castedPtr->EmitValue(std::forward(value)); }); } }; @@ -215,7 +215,7 @@ class EventSlot : public Event NodeId nodeId = castedPtr->GetInputNodeId(); auto& graphPtr = GetInternals(this->GetGroup()).GetGraphPtr(); - graphPtr->AddInput(nodeId, [this, castedPtr, &input] { castedPtr->AddInput(SameGroupOrLink(GetGroup(), input)); }); + graphPtr->PushInput(nodeId, [this, castedPtr, &input] { castedPtr->AddInput(SameGroupOrLink(GetGroup(), input)); }); } void RemoveInput(const Event& input) @@ -228,7 +228,7 @@ class EventSlot : public Event NodeId nodeId = castedPtr->GetInputNodeId(); auto& graphPtr = GetInternals(this->GetGroup()).GetGraphPtr(); - graphPtr->AddInput(nodeId, [this, castedPtr, &input] { castedPtr->RemoveInput(SameGroupOrLink(GetGroup(), input)); }); + graphPtr->PushInput(nodeId, [this, castedPtr, &input] { castedPtr->RemoveInput(SameGroupOrLink(GetGroup(), input)); }); } void RemoveAllInputs() @@ -241,7 +241,7 @@ class EventSlot : public Event NodeId nodeId = castedPtr->GetInputNodeId(); auto& graphPtr = GetInternals(this->GetGroup()).GetGraphPtr(); - graphPtr->AddInput(nodeId, [castedPtr] { castedPtr->RemoveAllInputs(); }); + graphPtr->PushInput(nodeId, [castedPtr] { castedPtr->RemoveAllInputs(); }); } }; @@ -309,8 +309,8 @@ auto Merge(const Event& dep1, const Event& ... deps) -> decltype(auto) template auto Filter(const Group& group, F&& pred, const Event& dep) -> Event { - auto filterFunc = [capturedPred = std::forward(pred)] (EventRange inRange, EventSink out) - { std::copy_if(inRange.begin(), inRange.end(), out, capturedPred); }; + auto filterFunc = [capturedPred = std::forward(pred)] (const EventValueList& evts, EventValueSink out) + { std::copy_if(evts.begin(), evts.end(), out, capturedPred); }; return Event(group, std::move(filterFunc), dep); } @@ -320,20 +320,20 @@ auto Filter(F&& pred, const Event& dep) -> Event { return Filter(dep.GetGroup(), std::forward(pred), dep); } template -auto Filter(const Group& group, F&& pred, const Event& dep, const Signal& ... signals) -> Event +auto Filter(const Group& group, F&& pred, const Event& dep, const State& ... states) -> Event { - auto filterFunc = [capturedPred = std::forward(pred)] (EventRange inRange, EventSink out, const Us& ... values) + auto filterFunc = [capturedPred = std::forward(pred)] (const EventValueList& evts, EventValueSink out, const Us& ... values) { - for (const auto& v : inRange) + for (const auto& v : evts) if (capturedPred(v, values ...)) *out++ = v; }; - return Event(group, std::move(filterFunc), dep, signals ...); + return Event(group, std::move(filterFunc), dep, State ...); } template -auto Filter(F&& pred, const Event& dep, const Signal& ... signals) -> Event +auto Filter(F&& pred, const Event& dep, const State& ... states) -> Event { return Filter(dep.GetGroup(), std::forward(pred), dep); } /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -353,7 +353,7 @@ auto Transform(F&& op, const Event& dep) -> Event { return Transform(dep.GetGroup(), std::forward(op), dep); } template -auto Transform(const Group& group, F&& op, const Event& dep, const Signal& ... signals) -> Event +auto Transform(const Group& group, F&& op, const Event& dep, const State& ... states) -> Event { auto transformFunc = [capturedOp = std::forward(pred)] (EventRange inRange, EventSink out, const Vs& ... values) { @@ -361,12 +361,12 @@ auto Transform(const Group& group, F&& op, const Event& dep, const Signal *out++ = capturedPred(v, values ...); }; - return Event(group, std::move(transformFunc), dep, signals ...); + return Event(group, std::move(transformFunc), dep, states ...); } template -auto Transform(F&& op, const Event& dep, const Signal& ... signals) -> Event - { return Transform(dep.GetGroup(), std::forward(op), dep, signals ...); } +auto Transform(F&& op, const Event& dep, const State& ... states) -> Event + { return Transform(dep.GetGroup(), std::forward(op), dep, states ...); } /////////////////////////////////////////////////////////////////////////////////////////////////// /// Join diff --git a/include/react/Observer.h b/include/react/Observer.h index 1f28136d..3f228ffd 100644 --- a/include/react/Observer.h +++ b/include/react/Observer.h @@ -18,39 +18,6 @@ #include "react/detail/observer_nodes.h" -/***************************************/ REACT_IMPL_BEGIN /**************************************/ - -class ObserverInternals -{ -public: - ObserverInternals(const ObserverInternals&) = default; - ObserverInternals& operator=(const ObserverInternals&) = default; - - ObserverInternals(ObserverInternals&&) = default; - ObserverInternals& operator=(ObserverInternals&&) = default; - - explicit ObserverInternals(std::shared_ptr&& nodePtr) : - nodePtr_( std::move(nodePtr) ) - { } - - auto GetNodePtr() -> std::shared_ptr& - { return nodePtr_; } - - auto GetNodePtr() const -> const std::shared_ptr& - { return nodePtr_; } - - NodeId GetNodeId() const - { return nodePtr_->GetNodeId(); } - -protected: - ObserverInternals() = default; - -private: - std::shared_ptr nodePtr_; -}; - -/****************************************/ REACT_IMPL_END /***************************************/ - /*****************************************/ REACT_BEGIN /*****************************************/ /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -68,16 +35,16 @@ class Observer : protected REACT_IMPL::ObserverInternals Observer(Observer&&) = default; Observer& operator=(Observer&&) = default; - // Construct signal observer with explicit group + // Construct state observer with explicit group template - Observer(const Group& group, F&& func, const Signal& subject1, const Signal& ... subjects) : - Observer::Observer( CreateSignalObserverNode(group, std::forward(func), subject1, subjects ...)) + Observer(const Group& group, F&& func, const State& subject1, const State& ... subjects) : + Observer::Observer( CreateStateObserverNode(group, std::forward(func), subject1, subjects ...)) { } - // Construct signal observer with implicit group + // Construct state observer with implicit group template - Observer(F&& func, const Signal& subject1, const Signal& ... subjects) : - Observer::Observer( CreateSignalObserverNode(subject1.GetGroup(), std::forward(func), subject1, subjects ...)) + Observer(F&& func, const State& subject1, const State& ... subjects) : + Observer::Observer( CreateStateObserverNode(subject1.GetGroup(), std::forward(func), subject1, subjects ...)) { } // Construct event observer with explicit group @@ -94,14 +61,14 @@ class Observer : protected REACT_IMPL::ObserverInternals // Constructed synced event observer with explicit group template - Observer(const Group& group, F&& func, const Event& subject, const Signal& ... signals) : - Observer::Observer( CreateSyncedEventObserverNode(group, std::forward(func), subject, signals ...)) + Observer(const Group& group, F&& func, const Event& subject, const State& ... states) : + Observer::Observer( CreateSyncedEventObserverNode(group, std::forward(func), subject, states ...)) { } // Constructed synced event observer with implicit group template - Observer(F&& func, const Event& subject, const Signal& ... signals) : - Observer::Observer( CreateSyncedEventObserverNode(subject.GetGroup(), std::forward(func), subject, signals ...)) + Observer(F&& func, const Event& subject, const State& ... states) : + Observer::Observer( CreateSyncedEventObserverNode(subject.GetGroup(), std::forward(func), subject, states ...)) { } public: //Internal @@ -112,10 +79,10 @@ class Observer : protected REACT_IMPL::ObserverInternals protected: template - auto CreateSignalObserverNode(const Group& group, F&& func, const Signal& dep1, const Signal& ... deps) -> decltype(auto) + auto CreateStateObserverNode(const Group& group, F&& func, const State& dep1, const State& ... deps) -> decltype(auto) { - using REACT_IMPL::SignalObserverNode; - return std::make_shared::type, T1, Ts ...>>( + using REACT_IMPL::StateObserverNode; + return std::make_shared::type, T1, Ts ...>>( group, std::forward(func), SameGroupOrLink(group, dep1), SameGroupOrLink(group, deps) ...); } @@ -128,7 +95,7 @@ class Observer : protected REACT_IMPL::ObserverInternals } template - auto CreateSyncedEventObserverNode(const Group& group, F&& func, const Event& dep, const Signal& ... syncs) -> decltype(auto) + auto CreateSyncedEventObserverNode(const Group& group, F&& func, const Event& dep, const State& ... syncs) -> decltype(auto) { using REACT_IMPL::SyncedEventObserverNode; return std::make_shared::type, T, Us ...>>( diff --git a/include/react/common/slotmap.h b/include/react/common/slotmap.h index c0282ec0..b5b51e21 100644 --- a/include/react/common/slotmap.h +++ b/include/react/common/slotmap.h @@ -1,5 +1,5 @@ -// Copyright Sebastian Jeckel 2016. +// Copyright Sebastian Jeckel 2017. // 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) diff --git a/include/react/common/syncpoint.h b/include/react/common/syncpoint.h index 7ca5586b..b4fc73f8 100644 --- a/include/react/common/syncpoint.h +++ b/include/react/common/syncpoint.h @@ -11,8 +11,10 @@ #include "react/detail/defs.h" +#include #include #include +#include #include @@ -23,20 +25,23 @@ /////////////////////////////////////////////////////////////////////////////////////////////////// class SyncPoint { -private: +public: class Dependency; - class ISyncPointState +private: + + + class ISyncTarget { public: - virtual ~ISyncPointState() = default; + virtual ~ISyncTarget() = default; virtual void IncrementWaitCount() = 0; virtual void DecrementWaitCount() = 0; }; - class SyncPointState : public ISyncPointState + class SyncPointState : public ISyncTarget { public: virtual void IncrementWaitCount() override @@ -81,14 +86,27 @@ class SyncPoint int waitCount_ = 0; }; - class SyncPointStateCollection : public ISyncPointState + class SyncTargetCollection : public ISyncTarget { - private: - std::vector + public: + virtual void IncrementWaitCount() override + { + for (const auto& e : targets) + e->IncrementWaitCount(); + } + + virtual void DecrementWaitCount() override + { + for (const auto& e : targets) + e->DecrementWaitCount(); + } + + std::vector> targets; }; public: - SyncPoint() : state_( std::make_shared() ) + SyncPoint() : + state_( std::make_shared() ) { } SyncPoint(const SyncPoint&) = default; @@ -123,67 +141,90 @@ class SyncPoint // Construct from single sync point. explicit Dependency(const SyncPoint& sp) : - state_( sp.state_ ) + target_( sp.state_ ) { - state_->IncrementWaitCount(); + target_->IncrementWaitCount(); } // Construct from vector of other dependencies. - explicit Dependency(std::vector&& others) : - state_( sp.state_ ) + template + Dependency(TBegin first, TEnd last) { - state_->IncrementWaitCount(); + auto count = std::distance(first, last); + + if (count == 1) + { + target_ = first->target_; + if (target_) + target_->IncrementWaitCount(); + } + else if (count > 1) + { + auto collection = std::make_shared(); + collection->targets.reserve(count); + + for (; !(first == last); ++first) + if (first->target_) // There's no point in propagating released/empty dependencies. + collection->targets.push_back(first->target_); + + collection->IncrementWaitCount(); + + target_ = std::move(collection); + } } Dependency(const Dependency& other) : - state_( other.state_ ) + target_( other.target_ ) { - state_->IncrementWaitCount(); + if (target_) + target_->IncrementWaitCount(); } Dependency& operator=(const Dependency& other) { - if (other.state_) - state_->IncrementWaitCount(); + if (other.target_) + other.target_->IncrementWaitCount(); - if (state_) - state_->DecrementWaitCount(); + if (target_) + target_->DecrementWaitCount(); - state_ = other.state_; + target_ = other.target_; + return *this; } Dependency(Dependency&& other) : - state_( std::move(other.state_) ) + target_( std::move(other.target_) ) { } Dependency& operator=(Dependency&& other) { - if (state_) - state_->DecrementWaitCount(); + if (target_) + target_->DecrementWaitCount(); - state_ = std::move(other.state_); + target_ = std::move(other.target_); + return *this; } ~Dependency() { - if (state_) - state_->DecrementWaitCount(); + if (target_) + target_->DecrementWaitCount(); } void Release() { - if (state_) + if (target_) { - state_->DecrementWaitCount(); - state_.reset(); + target_->DecrementWaitCount(); + target_ = nullptr; } } bool IsReleased() const - { return state_ == nullptr; } + { return target_ == nullptr; } private: - std::shared_ptr state_; + std::shared_ptr target_; }; private: diff --git a/include/react/common/utility.h b/include/react/common/utility.h index d1ce975d..8152ca3f 100644 --- a/include/react/common/utility.h +++ b/include/react/common/utility.h @@ -17,6 +17,34 @@ /***************************************/ REACT_IMPL_BEGIN /**************************************/ +template +struct Apply +{ + template + static auto apply(F&& f, T&& t, A&& ... a) -> decltype(auto) + { + return Apply::apply(std::forward(f), std::forward(t), std::get( + std::forward(t)), std::forward(a)...); + } +}; + +template<> +struct Apply<0> +{ + template + static auto apply(F&& f, T&&, A&& ... a) -> decltype(auto) + { + return std::forward(f)(std::forward(a) ...); + } +}; + +template +inline auto apply(F&& f, T&& t) -> decltype(auto) +{ + return Apply::type>::value>::apply( + std::forward(f), std::forward(t)); +} + /////////////////////////////////////////////////////////////////////////////////////////////////// /// Helper to enable calling a function on each element of an argument pack. /// We can't do f(args) ...; because ... expands with a comma. diff --git a/include/react/detail/algorithm_nodes.h b/include/react/detail/algorithm_nodes.h index 94cdde7e..b0a7d9da 100644 --- a/include/react/detail/algorithm_nodes.h +++ b/include/react/detail/algorithm_nodes.h @@ -14,8 +14,8 @@ #include #include +#include "state_nodes.h" #include "event_nodes.h" -#include "signal_nodes.h" /***************************************/ REACT_IMPL_BEGIN /**************************************/ @@ -23,12 +23,12 @@ /// IterateNode /////////////////////////////////////////////////////////////////////////////////////////////////// template -class IterateNode : public SignalNode +class IterateNode : public StateNode { public: template IterateNode(const Group& group, T&& init, FIn&& func, const Event& evnt) : - IterateNode::SignalNode( group, std::forward(init) ), + IterateNode::StateNode( group, std::forward(init) ), func_( std::forward(func) ), evnt_( evnt ) { @@ -66,12 +66,12 @@ class IterateNode : public SignalNode /// IterateByRefNode /////////////////////////////////////////////////////////////////////////////////////////////////// template -class IterateByRefNode : public SignalNode +class IterateByRefNode : public StateNode { public: template IterateByRefNode(const Group& group, T&& init, FIn&& func, const Event& evnt) : - IterateByRefNode::SignalNode( group, std::forward(init) ), + IterateByRefNode::StateNode( group, std::forward(init) ), func_( std::forward(func) ), evnt_( evnt ) { @@ -102,12 +102,12 @@ class IterateByRefNode : public SignalNode /// SyncedIterateNode /////////////////////////////////////////////////////////////////////////////////////////////////// template -class SyncedIterateNode : public SignalNode +class SyncedIterateNode : public StateNode { public: template - SyncedIterateNode(const Group& group, T&& init, FIn&& func, const Event& evnt, const Signal& ... syncs) : - SyncedIterateNode::SignalNode( group, std::forward(init) ), + SyncedIterateNode(const Group& group, T&& init, FIn&& func, const Event& evnt, const State& ... syncs) : + SyncedIterateNode::StateNode( group, std::forward(init) ), func_( std::forward(func) ), evnt_( evnt ), syncHolder_( syncs ... ) @@ -119,7 +119,7 @@ class SyncedIterateNode : public SignalNode ~SyncedIterateNode() { - std::apply([this] (const auto& ... syncs) { REACT_EXPAND_PACK(this->DetachFromMe(GetInternals(syncs).GetNodeId())); }, syncHolder_); + apply([this] (const auto& ... syncs) { REACT_EXPAND_PACK(this->DetachFromMe(GetInternals(syncs).GetNodeId())); }, syncHolder_); this->DetachFromMe(GetInternals(evnt_).GetNodeId()); this->UnregisterMe(); } @@ -130,7 +130,7 @@ class SyncedIterateNode : public SignalNode if (GetInternals(evnt_).Events().empty()) return UpdateResult::unchanged; - S newValue = std::apply( + S newValue = apply( [this] (const auto& ... syncs) { return func_(EventRange( GetInternals(evnt_).Events() ), this->Value(), GetInternals(syncs).Value() ...); @@ -152,19 +152,19 @@ class SyncedIterateNode : public SignalNode F func_; Event evnt_; - std::tuple ...> syncHolder_; + std::tuple ...> syncHolder_; }; /////////////////////////////////////////////////////////////////////////////////////////////////// /// SyncedIterateByRefNode /////////////////////////////////////////////////////////////////////////////////////////////////// template -class SyncedIterateByRefNode : public SignalNode +class SyncedIterateByRefNode : public StateNode { public: template - SyncedIterateByRefNode(const Group& group, T&& init, FIn&& func, const Event& evnt, const Signal& ... syncs) : - SyncedIterateByRefNode::SignalNode( group, std::forward(init) ), + SyncedIterateByRefNode(const Group& group, T&& init, FIn&& func, const Event& evnt, const State& ... syncs) : + SyncedIterateByRefNode::StateNode( group, std::forward(init) ), func_( std::forward(func) ), evnt_( evnt ), syncHolder_( syncs ... ) @@ -176,7 +176,7 @@ class SyncedIterateByRefNode : public SignalNode ~SyncedIterateByRefNode() { - std::apply([this] (const auto& ... syncs) { REACT_EXPAND_PACK(this->DetachFromMe(GetInternals(syncs).GetNodeId())); }, syncHolder_); + apply([this] (const auto& ... syncs) { REACT_EXPAND_PACK(this->DetachFromMe(GetInternals(syncs).GetNodeId())); }, syncHolder_); this->DetachFromMe(GetInternals(evnt_).GetNodeId()); this->UnregisterMe(); } @@ -187,7 +187,7 @@ class SyncedIterateByRefNode : public SignalNode if (GetInternals(evnt_).Events().empty()) return UpdateResult::unchanged; - std::apply( + apply( [this] (const auto& ... args) { func_(EventRange( GetInternals(evnt_).Events() ), this->Value(), GetInternals(args).Value() ...); @@ -201,19 +201,19 @@ class SyncedIterateByRefNode : public SignalNode F func_; Event events_; - std::tuple ...> syncHolder_; + std::tuple ...> syncHolder_; }; /////////////////////////////////////////////////////////////////////////////////////////////////// /// HoldNode /////////////////////////////////////////////////////////////////////////////////////////////////// template -class HoldNode : public SignalNode +class HoldNode : public StateNode { public: template HoldNode(const Group& group, T&& init, const Event& evnt) : - HoldNode::SignalNode( group, std::forward(init) ), + HoldNode::StateNode( group, std::forward(init) ), evnt_( evnt ) { this->RegisterMe(); @@ -255,11 +255,11 @@ class HoldNode : public SignalNode /// SnapshotNode /////////////////////////////////////////////////////////////////////////////////////////////////// template -class SnapshotNode : public SignalNode +class SnapshotNode : public StateNode { public: - SnapshotNode(const Group& group, const Signal& target, const Event& trigger) : - SnapshotNode::SignalNode( group, GetInternals(target).Value() ), + SnapshotNode(const Group& group, const State& target, const Event& trigger) : + SnapshotNode::StateNode( group, GetInternals(target).Value() ), target_( target ), trigger_( trigger ) { @@ -297,7 +297,7 @@ class SnapshotNode : public SignalNode } private: - Signal target_; + State target_; Event trigger_; }; @@ -308,7 +308,7 @@ template class MonitorNode : public EventStreamNode { public: - MonitorNode(const Group& group, const Signal& target) : + MonitorNode(const Group& group, const State& target) : MonitorNode::EventStreamNode( group ), target_( target ) { @@ -330,7 +330,7 @@ class MonitorNode : public EventStreamNode } private: - Signal target_; + State target_; }; /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -340,7 +340,7 @@ template class PulseNode : public EventStreamNode { public: - PulseNode(const Group& group, const Signal& target, const Event& trigger) : + PulseNode(const Group& group, const State& target, const Event& trigger) : PulseNode::EventStreamNode( group ), target_( target ), trigger_( trigger ) @@ -373,7 +373,7 @@ class PulseNode : public EventStreamNode } private: - Signal target_; + State target_; Event trigger_; }; diff --git a/include/react/detail/event_nodes.h b/include/react/detail/event_nodes.h index 1a2e1cdf..f422a903 100644 --- a/include/react/detail/event_nodes.h +++ b/include/react/detail/event_nodes.h @@ -20,7 +20,7 @@ //#include "tbb/spin_mutex.h" #include "node_base.h" -#include "react/common/Types.h" +#include "react/common/utility.h" /*****************************************/ REACT_BEGIN /*****************************************/ @@ -41,23 +41,23 @@ using EventValueSink = std::back_insert_iterator>; /// Forward declarations /////////////////////////////////////////////////////////////////////////////////////////////////// template -class SignalNode; +class StateNode; /////////////////////////////////////////////////////////////////////////////////////////////////// -/// EventStreamNode +/// EventNode /////////////////////////////////////////////////////////////////////////////////////////////////// template -class EventStreamNode : public NodeBase +class EventNode : public NodeBase { public: - EventStreamNode(EventStreamNode&&) = default; - EventStreamNode& operator=(EventStreamNode&&) = default; + EventNode(EventNode&&) = default; + EventNode& operator=(EventNode&&) = default; - EventStreamNode(const EventStreamNode&) = delete; - EventStreamNode& operator=(const EventStreamNode&) = delete; + EventNode(const EventNode&) = delete; + EventNode& operator=(const EventNode&) = delete; - explicit EventStreamNode(const Group& group) : - EventStreamNode::NodeBase( group ) + explicit EventNode(const Group& group) : + EventNode::NodeBase( group ) { } EventValueList& Events() @@ -77,11 +77,11 @@ class EventStreamNode : public NodeBase /// EventSourceNode /////////////////////////////////////////////////////////////////////////////////////////////////// template -class EventSourceNode : public EventStreamNode +class EventSourceNode : public EventNode { public: EventSourceNode(const Group& group) : - EventSourceNode::EventStreamNode( group ) + EventSourceNode::EventNode( group ) { this->RegisterMe(NodeCategory::input); } @@ -108,11 +108,11 @@ class EventSourceNode : public EventStreamNode /// EventMergeNode /////////////////////////////////////////////////////////////////////////////////////////////////// template -class EventMergeNode : public EventStreamNode +class EventMergeNode : public EventNode { public: EventMergeNode(const Group& group, const Event& ... deps) : - EventMergeNode::EventStreamNode( group ), + EventMergeNode::EventNode( group ), inputs_( deps ... ) { this->RegisterMe(); @@ -121,14 +121,14 @@ class EventMergeNode : public EventStreamNode ~EventMergeNode() { - std::apply([this] (const auto& ... deps) + apply([this] (const auto& ... deps) { REACT_EXPAND_PACK(this->DetachFromMe(GetInternals(deps).GetNodeId())); }, depHolder_); this->UnregisterMe(); } virtual UpdateResult Update(TurnId turnId) noexcept override { - std::apply([this] (auto& ... deps) + apply([this] (auto& ... deps) { REACT_EXPAND_PACK(MergeFromDep(deps)); }, depHolder_); if (! this->Events().empty()) @@ -152,11 +152,11 @@ class EventMergeNode : public EventStreamNode /// EventSlotNode /////////////////////////////////////////////////////////////////////////////////////////////////// template -class EventSlotNode : public EventStreamNode +class EventSlotNode : public EventNode { public: EventSlotNode(const Group& group) : - EventSlotNode::EventStreamNode( group ) + EventSlotNode::EventNode( group ) { inputNodeId_ = GetGraphPtr()->RegisterNode(&slotInput_, NodeCategory::dyninput); this->RegisterMe(); @@ -235,12 +235,12 @@ class EventSlotNode : public EventStreamNode /// EventProcessingNode /////////////////////////////////////////////////////////////////////////////////////////////////// template -class EventProcessingNode : public EventStreamNode +class EventProcessingNode : public EventNode { public: template EventProcessingNode(const Group& group, FIn&& func, const Event& dep) : - EventProcessingNode::EventStreamNode( group ), + EventProcessingNode::EventNode( group ), func_( std::forward(func) ), dep_( dep ) { @@ -256,7 +256,7 @@ class EventProcessingNode : public EventStreamNode virtual UpdateResult Update(TurnId turnId) noexcept override { - func_(EventRange( GetInternals(dep_).Events() ), std::back_inserter(this->Events())); + func_(GetInternals(dep_).Events(), std::back_inserter(this->Events())); if (! this->Events().empty()) return UpdateResult::changed; @@ -274,12 +274,12 @@ class EventProcessingNode : public EventStreamNode /// SyncedEventProcessingNode /////////////////////////////////////////////////////////////////////////////////////////////////// template -class SyncedEventProcessingNode : public EventStreamNode +class SyncedEventProcessingNode : public EventNode { public: template - SyncedEventProcessingNode(const Group& group, FIn&& func, const Event& dep, const Signal& ... syncs) : - SyncedEventProcessingNode::EventStreamNode( group ), + SyncedEventProcessingNode(const Group& group, FIn&& func, const Event& dep, const State& ... syncs) : + SyncedEventProcessingNode::EventNode( group ), func_( std::forward(func) ), dep_( dep ), syncHolder_( syncs ... ) @@ -291,7 +291,7 @@ class SyncedEventProcessingNode : public EventStreamNode ~SyncedEventProcessingNode() { - std::apply([this] (const auto& ... syncs) { REACT_EXPAND_PACK(this->DetachFromMe(syncs->GetNodeId())); }, syncHolder_); + apply([this] (const auto& ... syncs) { REACT_EXPAND_PACK(this->DetachFromMe(syncs->GetNodeId())); }, syncHolder_); this->DetachFromMe(dep_->GetNodeId()); this->UnregisterMe(); } @@ -302,7 +302,7 @@ class SyncedEventProcessingNode : public EventStreamNode if (dep_->Events().empty()) return UpdateResult::unchanged; - std::apply( + apply( [this] (const auto& ... syncs) { func_(EventRange( this->dep_->Events() ), std::back_inserter(this->Events()), syncs->Value() ...); @@ -320,18 +320,18 @@ class SyncedEventProcessingNode : public EventStreamNode Event dep_; - std::tuple ...> syncHolder_; + std::tuple ...> syncHolder_; }; /////////////////////////////////////////////////////////////////////////////////////////////////// /// EventJoinNode /////////////////////////////////////////////////////////////////////////////////////////////////// template -class EventJoinNode : public EventStreamNode> +class EventJoinNode : public EventNode> { public: EventJoinNode(const Group& group, const Event& ... deps) : - EventJoinNode::EventStreamNode( group ), + EventJoinNode::EventNode( group ), slots_( deps ... ) { this->RegisterMe(); @@ -340,21 +340,21 @@ class EventJoinNode : public EventStreamNode> ~EventJoinNode() { - std::apply([this] (const auto& ... slots) { REACT_EXPAND_PACK(this->DetachFromMe(GetInternals(slots.source).GetNodeId())); }, slots_); + apply([this] (const auto& ... slots) { REACT_EXPAND_PACK(this->DetachFromMe(GetInternals(slots.source).GetNodeId())); }, slots_); this->UnregisterMe(); } virtual UpdateResult Update(TurnId turnId) noexcept override { // Move events into buffers. - std::apply([this, turnId] (Slot& ... slots) { REACT_EXPAND_PACK(FetchBuffer(turnId, slots)); }, slots_); + apply([this, turnId] (Slot& ... slots) { REACT_EXPAND_PACK(FetchBuffer(turnId, slots)); }, slots_); while (true) { bool isReady = true; // All slots ready? - std::apply( + apply( [this, &isReady] (Slot& ... slots) { // Todo: combine return values instead @@ -366,7 +366,7 @@ class EventJoinNode : public EventStreamNode> break; // Pop values from buffers and emit tuple. - std::apply( + apply( [this] (Slot& ... slots) { this->Events().emplace_back(slots.buffer.front() ...); @@ -419,11 +419,11 @@ class EventJoinNode : public EventStreamNode> /// EventLinkNode /////////////////////////////////////////////////////////////////////////////////////////////////// template -class EventLinkNode : public EventStreamNode +class EventLinkNode : public EventNode { public: EventLinkNode(const Group& group, const Event& dep) : - EventLinkNode::EventStreamNode( group ), + EventLinkNode::EventNode( group ), linkOutput_( dep ) { this->RegisterMe(NodeCategory::input); @@ -480,7 +480,7 @@ class EventLinkNode : public EventStreamNode NodeId nodeId = storedParent->GetNodeId(); auto& graphPtr = storedParent->GetGraphPtr(); - graphPtr->AddInput(nodeId, + graphPtr->PushInput(nodeId, [&storedParent, &storedEvents] { storedParent->SetEvents(std::move(storedEvents)); @@ -512,14 +512,14 @@ class EventInternals EventInternals(EventInternals&&) = default; EventInternals& operator=(EventInternals&&) = default; - explicit EventInternals(std::shared_ptr>&& nodePtr) : + explicit EventInternals(std::shared_ptr>&& nodePtr) : nodePtr_( std::move(nodePtr) ) { } - auto GetNodePtr() -> std::shared_ptr>& + auto GetNodePtr() -> std::shared_ptr>& { return nodePtr_; } - auto GetNodePtr() const -> const std::shared_ptr>& + auto GetNodePtr() const -> const std::shared_ptr>& { return nodePtr_; } NodeId GetNodeId() const @@ -532,7 +532,7 @@ class EventInternals { return nodePtr_->Events(); } private: - std::shared_ptr> nodePtr_; + std::shared_ptr> nodePtr_; }; /****************************************/ REACT_IMPL_END /***************************************/ diff --git a/include/react/detail/graph_impl.h b/include/react/detail/graph_impl.h index 133ffbe6..42c04789 100644 --- a/include/react/detail/graph_impl.h +++ b/include/react/detail/graph_impl.h @@ -18,7 +18,6 @@ #include #include #include -#include #include #include @@ -39,16 +38,10 @@ class TransactionQueue graph_( graph ) { } - TransactionQueue(const TransactionQueue&) = delete; - TransactionQueue& operator=(const TransactionQueue&) = delete; - - TransactionQueue(TransactionQueue&&) = default; - TransactionQueue& operator =(TransactionQueue&&) = default; - template void Push(F&& func, SyncPoint::Dependency dep, TransactionFlags flags) { - transactions_.push(StoredTransaction{ std::forward(transaction), std::move(dep), flags }); + transactions_.push(StoredTransaction{ std::forward(func), std::move(dep), flags }); if (count_.fetch_add(1, std::memory_order_release) == 0) tbb::task::enqueue(*new(tbb::task::allocate_root()) WorkerTask(*this)); @@ -57,9 +50,9 @@ class TransactionQueue private: struct StoredTransaction { - std::function func; - SyncPoint::DependencyList deps; - TransactionFlags flags; + std::function func; + SyncPoint::Dependency dep; + TransactionFlags flags; }; class WorkerTask : public tbb::task @@ -67,7 +60,7 @@ class TransactionQueue public: WorkerTask(TransactionQueue& parent) : parent_( parent ) - { } + { } tbb::task* execute() { @@ -104,13 +97,15 @@ class ReactGraph template void PushInput(NodeId nodeId, F&& inputCallback); - void PushDependency(SyncPoint::Dependency dep); + void AddSyncPointDependency(SyncPoint::Dependency dep, bool syncLinked); + + void AllowLinkedTransactionMerging(bool allowMerging); template void DoTransaction(F&& transactionCallback); template - void EnqueueTransaction(F&& func, SyncPoint::DependencyList&& deps, TransactionFlags flags); + void EnqueueTransaction(F&& func, SyncPoint::Dependency dep, TransactionFlags flags); LinkCache& GetLinkCache() { return linkCache_; } @@ -173,18 +168,20 @@ class ReactGraph SlotMap nodeData_; - TopoQueue scheduledNodes_; + TopoQueue scheduledNodes_; std::vector changedInputs_; std::vector changedNodes_; - std::vector curDependencies_; + LinkOutputMap scheduledLinkOutputs_; - LinkOutputMap scheduledLinkOutputs_; + std::vector localDependencies_; + std::vector linkDependencies_; - LinkCache linkCache_; + LinkCache linkCache_; bool isTransactionActive_ = false; + bool allowLinkedTransactionMerging_ = false; }; template @@ -214,9 +211,9 @@ void ReactGraph::DoTransaction(F&& transactionCallback) } template -void ReactGraph::EnqueueTransaction(F&& func, SyncPoint::DependencyList&& deps, TransactionFlags flags) +void ReactGraph::EnqueueTransaction(F&& func, SyncPoint::Dependency dep, TransactionFlags flags) { - transactionQueue_.Push(std::forward(func), std::move(deps), flags); + transactionQueue_.Push(std::forward(func), std::move(dep), flags); } /****************************************/ REACT_IMPL_END /***************************************/ diff --git a/include/react/detail/observer_nodes.h b/include/react/detail/observer_nodes.h index 35c160b1..9634c89c 100644 --- a/include/react/detail/observer_nodes.h +++ b/include/react/detail/observer_nodes.h @@ -11,9 +11,11 @@ #include "react/detail/defs.h" #include "react/api.h" +#include "react/common/utility.h" #include #include +#include #include "node_base.h" @@ -23,13 +25,13 @@ /// Forward declarations /////////////////////////////////////////////////////////////////////////////////////////////////// template -class SignalNode; +class StateNode; template class EventStreamNode; /////////////////////////////////////////////////////////////////////////////////////////////////// -/// SignalObserverNode +/// StateObserverNode /////////////////////////////////////////////////////////////////////////////////////////////////// class ObserverNode : public NodeBase { @@ -40,39 +42,43 @@ class ObserverNode : public NodeBase }; /////////////////////////////////////////////////////////////////////////////////////////////////// -/// SignalObserverNode +/// StateObserverNode /////////////////////////////////////////////////////////////////////////////////////////////////// template -class SignalObserverNode : public ObserverNode +class StateObserverNode : public ObserverNode { public: template - SignalObserverNode(const Group& group, FIn&& func, const Signal& ... deps) : - SignalObserverNode::ObserverNode( group ), + StateObserverNode(const Group& group, FIn&& func, const State& ... deps) : + StateObserverNode::ObserverNode( group ), func_( std::forward(func) ), depHolder_( deps ... ) { this->RegisterMe(NodeCategory::output); REACT_EXPAND_PACK(this->AttachToMe(GetInternals(deps).GetNodeId())); + + apply([this] (const auto& ... deps) + { this->func_(GetInternals(deps).Value() ...); }, depHolder_); } - ~SignalObserverNode() + ~StateObserverNode() { - std::apply([this] (const auto& ... deps) + apply([this] (const auto& ... deps) { REACT_EXPAND_PACK(this->DetachFromMe(GetInternals(deps).GetNodeId())); }, depHolder_); this->UnregisterMe(); } virtual UpdateResult Update(TurnId turnId) noexcept override { - std::apply([this] (const auto& ... deps) { this->func_(GetInternals(deps).Value() ...); }, depHolder_); + apply([this] (const auto& ... deps) + { this->func_(GetInternals(deps).Value() ...); }, depHolder_); return UpdateResult::unchanged; } private: F func_; - std::tuple ...> depHolder_; + std::tuple ...> depHolder_; }; /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -118,7 +124,7 @@ class SyncedEventObserverNode : public ObserverNode { public: template - SyncedEventObserverNode(const Group& group, FIn&& func, const Event& subject, const Signal& ... syncs) : + SyncedEventObserverNode(const Group& group, FIn&& func, const Event& subject, const State& ... syncs) : SyncedEventObserverNode::ObserverNode( group ), func_( std::forward(func) ), subject_( subject ), @@ -131,7 +137,7 @@ class SyncedEventObserverNode : public ObserverNode ~SyncedEventObserverNode() { - std::apply([this] (const auto& ... syncs) + apply([this] (const auto& ... syncs) { REACT_EXPAND_PACK(this->DetachFromMe(GetInternals(syncs).GetNodeId())); }, syncHolder_); this->DetachFromMe(GetInternals(subject_).GetNodeId()); this->UnregisterMe(); @@ -143,7 +149,7 @@ class SyncedEventObserverNode : public ObserverNode if (GetInternals(this->subject_).Events().empty()) return UpdateResult::unchanged; - std::apply([this] (const auto& ... syncs) + apply([this] (const auto& ... syncs) { func_(EventRange( GetInternals(this->subject_).Events() ), GetInternals(syncs).Value() ...); }, syncHolder_); return UpdateResult::unchanged; @@ -154,7 +160,39 @@ class SyncedEventObserverNode : public ObserverNode Event subject_; - std::tuple ...> syncHolder_; + std::tuple ...> syncHolder_; +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// ObserverInternals +/////////////////////////////////////////////////////////////////////////////////////////////////// +class ObserverInternals +{ +public: + ObserverInternals(const ObserverInternals&) = default; + ObserverInternals& operator=(const ObserverInternals&) = default; + + ObserverInternals(ObserverInternals&&) = default; + ObserverInternals& operator=(ObserverInternals&&) = default; + + explicit ObserverInternals(std::shared_ptr&& nodePtr) : + nodePtr_( std::move(nodePtr) ) + { } + + auto GetNodePtr() -> std::shared_ptr& + { return nodePtr_; } + + auto GetNodePtr() const -> const std::shared_ptr& + { return nodePtr_; } + + NodeId GetNodeId() const + { return nodePtr_->GetNodeId(); } + +protected: + ObserverInternals() = default; + +private: + std::shared_ptr nodePtr_; }; /****************************************/ REACT_IMPL_END /***************************************/ diff --git a/include/react/detail/signal_nodes.h b/include/react/detail/state_nodes.h similarity index 75% rename from include/react/detail/signal_nodes.h rename to include/react/detail/state_nodes.h index f97dc908..655ab542 100644 --- a/include/react/detail/signal_nodes.h +++ b/include/react/detail/state_nodes.h @@ -6,8 +6,8 @@ #pragma once -#ifndef REACT_DETAIL_GRAPH_SIGNALNODES_H_INCLUDED -#define REACT_DETAIL_GRAPH_SIGNALNODES_H_INCLUDED +#ifndef REACT_DETAIL_GRAPH_STATENODES_H_INCLUDED +#define REACT_DETAIL_GRAPH_STATENODES_H_INCLUDED #include "react/detail/defs.h" @@ -27,26 +27,26 @@ template bool Equals(const L& lhs, const R& rhs); /////////////////////////////////////////////////////////////////////////////////////////////////// -/// SignalNode +/// StateNode /////////////////////////////////////////////////////////////////////////////////////////////////// template -class SignalNode : public NodeBase +class StateNode : public NodeBase { public: - SignalNode(SignalNode&&) = default; - SignalNode& operator=(SignalNode&&) = default; + StateNode(StateNode&&) = default; + StateNode& operator=(StateNode&&) = default; - SignalNode(const SignalNode&) = delete; - SignalNode& operator=(const SignalNode&) = delete; + StateNode(const StateNode&) = delete; + StateNode& operator=(const StateNode&) = delete; - explicit SignalNode(const Group& group) : - SignalNode::NodeBase( group ), + explicit StateNode(const Group& group) : + StateNode::NodeBase( group ), value_( ) { } template - SignalNode(const Group& group, T&& value) : - SignalNode::NodeBase( group ), + StateNode(const Group& group, T&& value) : + StateNode::NodeBase( group ), value_( std::forward(value) ) { } @@ -64,25 +64,25 @@ class SignalNode : public NodeBase /// VarNode /////////////////////////////////////////////////////////////////////////////////////////////////// template -class VarSignalNode : public SignalNode +class StateVarNode : public StateNode { public: - explicit VarSignalNode(const Group& group) : - VarSignalNode::SignalNode( group ), + explicit StateVarNode(const Group& group) : + StateVarNode::StateNode( group ), newValue_( ) { this->RegisterMe(NodeCategory::input); } template - VarSignalNode(const Group& group, T&& value) : - VarSignalNode::SignalNode( group, std::forward(value) ), + StateVarNode(const Group& group, T&& value) : + StateVarNode::StateNode( group, std::forward(value) ), newValue_( value ) { this->RegisterMe(); } - ~VarSignalNode() + ~StateVarNode() { this->UnregisterMe(); } @@ -127,7 +127,6 @@ class VarSignalNode : public SignalNode isInputModified_ = false; } - // This is signal-specific template void ModifyValue(F&& func) { @@ -154,15 +153,15 @@ class VarSignalNode : public SignalNode }; /////////////////////////////////////////////////////////////////////////////////////////////////// -/// SignalOpNode +/// StateOpNode /////////////////////////////////////////////////////////////////////////////////////////////////// template -class SignalFuncNode : public SignalNode +class StateFuncNode : public StateNode { public: template - SignalFuncNode(const Group& group, FIn&& func, const Signal& ... deps) : - SignalFuncNode::SignalNode( group, func(GetInternals(deps).Value() ...) ), + StateFuncNode(const Group& group, FIn&& func, const State& ... deps) : + StateFuncNode::StateNode( group, func(GetInternals(deps).Value() ...) ), func_( std::forward(func) ), depHolder_( deps ... ) { @@ -170,9 +169,9 @@ class SignalFuncNode : public SignalNode REACT_EXPAND_PACK(this->AttachToMe(GetInternals(deps).GetNodeId())); } - ~SignalFuncNode() + ~StateFuncNode() { - std::apply([this] (const auto& ... deps) + apply([this] (const auto& ... deps) { REACT_EXPAND_PACK(this->DetachFromMe(GetInternals(deps).GetNodePtr()->GetNodeId())); }, depHolder_); this->UnregisterMe(); } @@ -181,7 +180,7 @@ class SignalFuncNode : public SignalNode { bool changed = false; - S newValue = std::apply([this] (const auto& ... deps) + S newValue = apply([this] (const auto& ... deps) { return this->func_(GetInternals(deps).Value() ...); }, depHolder_); if (! (this->Value() == newValue)) @@ -198,18 +197,18 @@ class SignalFuncNode : public SignalNode private: F func_; - std::tuple ...> depHolder_; + std::tuple ...> depHolder_; }; /////////////////////////////////////////////////////////////////////////////////////////////////// -/// SignalSlotNode +/// StateSlotNode /////////////////////////////////////////////////////////////////////////////////////////////////// template -class SignalSlotNode : public SignalNode +class StateSlotNode : public StateNode { public: - SignalSlotNode(const Group& group, const Signal& dep) : - SignalSlotNode::SignalNode( group, GetInternals(dep).Value() ), + StateSlotNode(const Group& group, const State& dep) : + StateSlotNode::StateNode( group, GetInternals(dep).Value() ), input_( dep ) { inputNodeId_ = GetGraphPtr()->RegisterNode(&slotInput_, NodeCategory::dyninput); @@ -219,7 +218,7 @@ class SignalSlotNode : public SignalNode this->AttachToMe(GetInternals(dep).GetNodeId()); } - ~SignalSlotNode() + ~StateSlotNode() { this->DetachFromMe(GetInternals(input_).GetNodeId()); this->DetachFromMe(inputNodeId_); @@ -241,7 +240,7 @@ class SignalSlotNode : public SignalNode } } - void SetInput(const Signal& newInput) + void SetInput(const State& newInput) { if (newInput == input_) return; @@ -262,36 +261,35 @@ class SignalSlotNode : public SignalNode { return UpdateResult::changed; } }; - Signal input_; + State input_; NodeId inputNodeId_; VirtualInputNode slotInput_; }; /////////////////////////////////////////////////////////////////////////////////////////////////// -/// SignalLinkNode +/// StateLinkNode /////////////////////////////////////////////////////////////////////////////////////////////////// template -class SignalLinkNode : public SignalNode +class StateLinkNode : public StateNode { public: - SignalLinkNode(const Group& group, const Signal& dep) : - SignalLinkNode::SignalNode( group, GetInternals(dep).Value() ), - dep_ ( dep ) + StateLinkNode(const Group& group, const State& dep) : + StateLinkNode::StateNode( group, GetInternals(dep).Value() ), + dep_ ( dep ), + srcGroup_( dep.GetGroup() ) { this->RegisterMe(NodeCategory::input); - auto& srcGraphPtr = GetInternals(srcGroup).GetGraphPtr(); - outputNodeId_ = srcGraphPtr->RegisterNode(this, NodeCategory::linkoutput); + auto& srcGraphPtr = GetInternals(srcGroup_).GetGraphPtr(); + outputNodeId_ = srcGraphPtr->RegisterNode(&linkOutput_, NodeCategory::linkoutput); srcGraphPtr->AttachNode(outputNodeId_, GetInternals(dep).GetNodeId()); } - ~SignalLinkNode() + ~StateLinkNode() { - this->DetachFromMe(GetInternals(dep_).GetNodeId()); - - auto& srcGraphPtr = GetInternals(srcGroup).GetGraphPtr(); + auto& srcGraphPtr = GetInternals(srcGroup_).GetGraphPtr(); srcGraphPtr->DetachNode(outputNodeId_, GetInternals(dep_).GetNodeId()); srcGraphPtr->UnregisterNode(outputNodeId_); @@ -301,7 +299,7 @@ class SignalLinkNode : public SignalNode this->UnregisterMe(); } - void SetWeakSelfPtr(const std::weak_ptr& self) + void SetWeakSelfPtr(const std::weak_ptr& self) { linkOutput_.parent = self; } virtual UpdateResult Update(TurnId turnId) noexcept override @@ -327,7 +325,7 @@ class SignalLinkNode : public SignalNode NodeId nodeId = storedParent->GetNodeId(); auto& graphPtr = storedParent->GetGraphPtr(); - graphPtr->AddInput(nodeId, + graphPtr->PushInput(nodeId, [&storedParent, &storedValue] { storedParent->SetValue(std::move(storedValue)); @@ -336,37 +334,38 @@ class SignalLinkNode : public SignalNode } } - std::weak_ptr parent; + std::weak_ptr parent; }; - Signal dep_; - Group srcGroup; + State dep_; + Group srcGroup_; NodeId outputNodeId_; + VirtualOutputNode linkOutput_; }; /////////////////////////////////////////////////////////////////////////////////////////////////// -/// SignalInternals +/// StateInternals /////////////////////////////////////////////////////////////////////////////////////////////////// template -class SignalInternals +class StateInternals { public: - SignalInternals(const SignalInternals&) = default; - SignalInternals& operator=(const SignalInternals&) = default; + StateInternals(const StateInternals&) = default; + StateInternals& operator=(const StateInternals&) = default; - SignalInternals(SignalInternals&&) = default; - SignalInternals& operator=(SignalInternals&&) = default; + StateInternals(StateInternals&&) = default; + StateInternals& operator=(StateInternals&&) = default; - explicit SignalInternals(std::shared_ptr>&& nodePtr) : + explicit StateInternals(std::shared_ptr>&& nodePtr) : nodePtr_( std::move(nodePtr) ) { } - auto GetNodePtr() -> std::shared_ptr>& + auto GetNodePtr() -> std::shared_ptr>& { return nodePtr_; } - auto GetNodePtr() const -> const std::shared_ptr>& + auto GetNodePtr() const -> const std::shared_ptr>& { return nodePtr_; } NodeId GetNodeId() const @@ -379,9 +378,9 @@ class SignalInternals { return nodePtr_->Value(); } private: - std::shared_ptr> nodePtr_; + std::shared_ptr> nodePtr_; }; /****************************************/ REACT_IMPL_END /***************************************/ -#endif // REACT_DETAIL_GRAPH_SIGNALNODES_H_INCLUDED \ No newline at end of file +#endif // REACT_DETAIL_GRAPH_STATENODES_H_INCLUDED \ No newline at end of file diff --git a/include/react/Signal.h b/include/react/state.h similarity index 51% rename from include/react/Signal.h rename to include/react/state.h index c7e11e8f..95d80b6c 100644 --- a/include/react/Signal.h +++ b/include/react/state.h @@ -4,8 +4,8 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -#ifndef REACT_SIGNAL_H_INCLUDED -#define REACT_SIGNAL_H_INCLUDED +#ifndef REACT_STATE_H_INCLUDED +#define REACT_STATE_H_INCLUDED #pragma once @@ -19,34 +19,34 @@ #include #include -#include "react/detail/signal_nodes.h" +#include "react/detail/state_nodes.h" /*****************************************/ REACT_BEGIN /*****************************************/ /////////////////////////////////////////////////////////////////////////////////////////////////// -/// Signal +/// State /////////////////////////////////////////////////////////////////////////////////////////////////// template -class Signal : protected REACT_IMPL::SignalInternals +class State : protected REACT_IMPL::StateInternals { public: - Signal(const Signal&) = default; - Signal& operator=(const Signal&) = default; + State(const State&) = default; + State& operator=(const State&) = default; - Signal(Signal&&) = default; - Signal& operator=(Signal&&) = default; + State(State&&) = default; + State& operator=(State&&) = default; // Construct with explicit group template - explicit Signal(const Group& group, F&& func, const Signal& dep1, const Signal& ... deps) : - Signal::SignalInternals( CreateFuncNode(group, std::forward(func), dep1, deps ...) ) + explicit State(const Group& group, F&& func, const State& dep1, const State& ... deps) : + State::StateInternals( CreateFuncNode(group, std::forward(func), dep1, deps ...) ) { } // Construct with implicit group template - explicit Signal(F&& func, const Signal& dep1, const Signal& ... deps) : - Signal::SignalInternals( CreateFuncNode(dep1.GetGroup(), std::forward(func), dep1, deps ...) ) + explicit State(F&& func, const State& dep1, const State& ... deps) : + State::StateInternals( CreateFuncNode(dep1.GetGroup(), std::forward(func), dep1, deps ...) ) { } auto GetGroup() const -> const Group& @@ -55,31 +55,31 @@ class Signal : protected REACT_IMPL::SignalInternals auto GetGroup() -> Group& { return this->GetNodePtr()->GetGroup(); } - friend bool operator==(const Signal& a, const Signal& b) + friend bool operator==(const State& a, const State& b) { return a.GetNodePtr() == b.GetNodePtr(); } - friend bool operator!=(const Signal& a, const Signal& b) + friend bool operator!=(const State& a, const State& b) { return !(a == b); } - friend auto GetInternals(Signal& s) -> REACT_IMPL::SignalInternals& + friend auto GetInternals(State& s) -> REACT_IMPL::StateInternals& { return s; } - friend auto GetInternals(const Signal& s) -> const REACT_IMPL::SignalInternals& + friend auto GetInternals(const State& s) -> const REACT_IMPL::StateInternals& { return s; } protected: - explicit Signal(std::shared_ptr>&& nodePtr) : - Signal::SignalInternals( std::move(nodePtr) ) + explicit State(std::shared_ptr>&& nodePtr) : + State::StateInternals( std::move(nodePtr) ) { } private: template - auto CreateFuncNode(const Group& group, F&& func, const Signal& dep1, const Signal& ... deps) -> decltype(auto) + auto CreateFuncNode(const Group& group, F&& func, const State& dep1, const State& ... deps) -> decltype(auto) { - using REACT_IMPL::SignalFuncNode; + using REACT_IMPL::StateFuncNode; using REACT_IMPL::SameGroupOrLink; - return std::make_shared::type, T1, Ts ...>>( + return std::make_shared::type, T1, Ts ...>>( group, std::forward(func), SameGroupOrLink(group, dep1), SameGroupOrLink(group, deps) ...); } @@ -88,27 +88,27 @@ class Signal : protected REACT_IMPL::SignalInternals }; /////////////////////////////////////////////////////////////////////////////////////////////////// -/// VarSignal +/// StateVar /////////////////////////////////////////////////////////////////////////////////////////////////// template -class VarSignal : public Signal +class StateVar : public State { public: - VarSignal(const VarSignal&) = default; - VarSignal& operator=(const VarSignal&) = default; + StateVar(const StateVar&) = default; + StateVar& operator=(const StateVar&) = default; - VarSignal(VarSignal&&) = default; - VarSignal& operator=(VarSignal&&) = default; + StateVar(StateVar&&) = default; + StateVar& operator=(StateVar&&) = default; // Construct with group + default - explicit VarSignal(const Group& group) : - VarSignal::Signal( CreateVarNode(group) ) + explicit StateVar(const Group& group) : + StateVar::State( CreateVarNode(group) ) { } // Construct with group + value template - VarSignal(const Group& group, T&& value) : - VarSignal::Signal( CreateVarNode(group, std::forward(value)) ) + StateVar(const Group& group, T&& value) : + StateVar::State( CreateVarNode(group, std::forward(value)) ) { } void Set(const S& newValue) @@ -121,140 +121,140 @@ class VarSignal : public Signal void Modify(const F& func) { ModifyValue(func); } - friend bool operator==(const VarSignal& a, VarSignal& b) + friend bool operator==(const StateVar& a, StateVar& b) { return a.GetNodePtr() == b.GetNodePtr(); } - friend bool operator!=(const VarSignal& a, VarSignal& b) + friend bool operator!=(const StateVar& a, StateVar& b) { return !(a == b); } protected: - explicit VarSignal(std::shared_ptr>&& nodePtr) : - VarSignal::Signal( std::move(nodePtr) ) + explicit StateVar(std::shared_ptr>&& nodePtr) : + StateVar::State( std::move(nodePtr) ) { } private: static auto CreateVarNode(const Group& group) -> decltype(auto) { - using REACT_IMPL::VarSignalNode; - return std::make_shared>(group); + using REACT_IMPL::StateVarNode; + return std::make_shared>(group); } template static auto CreateVarNode(const Group& group, T&& value) -> decltype(auto) { - using REACT_IMPL::VarSignalNode; - return std::make_shared>(group, std::forward(value)); + using REACT_IMPL::StateVarNode; + return std::make_shared>(group, std::forward(value)); } template void SetValue(T&& newValue) { using REACT_IMPL::NodeId; - using VarNodeType = REACT_IMPL::VarSignalNode; + using VarNodeType = REACT_IMPL::StateVarNode; VarNodeType* castedPtr = static_cast(this->GetNodePtr().get()); NodeId nodeId = castedPtr->GetNodeId(); auto& graphPtr = GetInternals(this->GetGroup()).GetGraphPtr(); - graphPtr->AddInput(nodeId, [castedPtr, &newValue] { castedPtr->SetValue(std::forward(newValue)); }); + graphPtr->PushInput(nodeId, [castedPtr, &newValue] { castedPtr->SetValue(std::forward(newValue)); }); } template void ModifyValue(const F& func) { using REACT_IMPL::NodeId; - using VarNodeType = REACT_IMPL::VarSignalNode; + using VarNodeType = REACT_IMPL::StateVarNode; VarNodeType* castedPtr = static_cast(this->GetNodePtr().get()); NodeId nodeId = castedPtr->GetNodeId(); auto& graphPtr = GetInternals(this->GetGroup()).GetGraphPtr(); - graphPtr->AddInput(nodeId, [castedPtr, &func] { castedPtr->ModifyValue(func); }); + graphPtr->PushInput(nodeId, [castedPtr, &func] { castedPtr->ModifyValue(func); }); } }; /////////////////////////////////////////////////////////////////////////////////////////////////// -/// SignalSlotBase +/// StateSlotBase /////////////////////////////////////////////////////////////////////////////////////////////////// template -class SignalSlot : public Signal +class StateSlot : public State { public: - SignalSlot(const SignalSlot&) = default; - SignalSlot& operator=(const SignalSlot&) = default; + StateSlot(const StateSlot&) = default; + StateSlot& operator=(const StateSlot&) = default; - SignalSlot(SignalSlot&&) = default; - SignalSlot& operator=(SignalSlot&&) = default; + StateSlot(StateSlot&&) = default; + StateSlot& operator=(StateSlot&&) = default; // Construct with explicit group - SignalSlot(const Group& group, const Signal& input) : - SignalSlot::Signal( CreateSlotNode(group, input) ) + StateSlot(const Group& group, const State& input) : + StateSlot::State( CreateSlotNode(group, input) ) { } // Construct with implicit group - explicit SignalSlot(const Signal& input) : - SignalSlot::Signal( CreateSlotNode(input.GetGroup(), input) ) + explicit StateSlot(const State& input) : + StateSlot::State( CreateSlotNode(input.GetGroup(), input) ) { } - void Set(const Signal& newInput) + void Set(const State& newInput) { SetInput(newInput); } - void operator<<=(const Signal& newInput) + void operator<<=(const State& newInput) { SetInput(newInput); } protected: - explicit SignalSlot(std::shared_ptr>&& nodePtr) : - SignalSlot::Signal( std::move(nodePtr) ) + explicit StateSlot(std::shared_ptr>&& nodePtr) : + StateSlot::State( std::move(nodePtr) ) { } private: - static auto CreateSlotNode(const Group& group, const Signal& input) -> decltype(auto) + static auto CreateSlotNode(const Group& group, const State& input) -> decltype(auto) { - using REACT_IMPL::SignalSlotNode; + using REACT_IMPL::StateSlotNode; using REACT_IMPL::SameGroupOrLink; - return std::make_shared>(group, SameGroupOrLink(group, input)); + return std::make_shared>(group, SameGroupOrLink(group, input)); } - void SetInput(const Signal& newInput) + void SetInput(const State& newInput) { using REACT_IMPL::NodeId; - using REACT_IMPL::SignalSlotNode; + using REACT_IMPL::StateSlotNode; using REACT_IMPL::SameGroupOrLink; - auto* castedPtr = static_cast*>(this->GetNodePtr().get()); + auto* castedPtr = static_cast*>(this->GetNodePtr().get()); NodeId nodeId = castedPtr->GetInputNodeId(); auto& graphPtr = GetInternals(this->GetGroup()).GetGraphPtr(); - graphPtr->AddInput(nodeId, [this, castedPtr, &newInput] { castedPtr->SetInput(SameGroupOrLink(GetGroup(), newInput)); }); + graphPtr->PushInput(nodeId, [this, castedPtr, &newInput] { castedPtr->SetInput(SameGroupOrLink(GetGroup(), newInput)); }); } }; /////////////////////////////////////////////////////////////////////////////////////////////////// -/// SignalLink +/// StateLink /////////////////////////////////////////////////////////////////////////////////////////////////// template -class SignalLink : public Signal +class StateLink : public State { public: - SignalLink(const SignalLink&) = default; - SignalLink& operator=(const SignalLink&) = default; + StateLink(const StateLink&) = default; + StateLink& operator=(const StateLink&) = default; - SignalLink(SignalLink&&) = default; - SignalLink& operator=(SignalLink&&) = default; + StateLink(StateLink&&) = default; + StateLink& operator=(StateLink&&) = default; // Construct with group - SignalLink(const Group& group, const Signal& input) : - SignalLink::Signal( GetOrCreateLinkNode(group, input) ) + StateLink(const Group& group, const State& input) : + StateLink::State( GetOrCreateLinkNode(group, input) ) { } protected: - static auto GetOrCreateLinkNode(const Group& group, const Signal& input) -> decltype(auto) + static auto GetOrCreateLinkNode(const Group& group, const State& input) -> decltype(auto) { - using REACT_IMPL::SignalLinkNode; + using REACT_IMPL::StateLinkNode; using REACT_IMPL::IReactNode; using REACT_IMPL::ReactGraph; @@ -266,12 +266,12 @@ class SignalLink : public Signal k, [&] { - auto nodePtr = std::make_shared>(group, input); - nodePtr->SetWeakSelfPtr(std::weak_ptr>{ nodePtr }); + auto nodePtr = std::make_shared>(group, input); + nodePtr->SetWeakSelfPtr(std::weak_ptr>{ nodePtr }); return std::static_pointer_cast(nodePtr); }); - return std::static_pointer_cast>(nodePtr); + return std::static_pointer_cast>(nodePtr); } }; @@ -280,14 +280,14 @@ class SignalLink : public Signal /***************************************/ REACT_IMPL_BEGIN /**************************************/ template -static Signal SameGroupOrLink(const Group& targetGroup, const Signal& dep) +static State SameGroupOrLink(const Group& targetGroup, const State& dep) { if (dep.GetGroup() == targetGroup) return dep; else - return SignalLink( targetGroup, dep ); + return StateLink( targetGroup, dep ); } /****************************************/ REACT_IMPL_END /***************************************/ -#endif // REACT_SIGNAL_H_INCLUDED \ No newline at end of file +#endif // REACT_STATE_H_INCLUDED \ No newline at end of file diff --git a/project/msvc/CppReact.vcxproj b/project/msvc/CppReact.vcxproj index 68b88817..1867d880 100644 --- a/project/msvc/CppReact.vcxproj +++ b/project/msvc/CppReact.vcxproj @@ -106,7 +106,6 @@ $(SolutionDir)..\..\include;%(AdditionalIncludeDirectories) true %(PreprocessorDefinitions) - stdcpp17 true @@ -145,7 +144,6 @@ $(SolutionDir)..\..\include;%(AdditionalIncludeDirectories) true %(PreprocessorDefinitions) - stdcpp17 true @@ -170,11 +168,11 @@ - + - + diff --git a/project/msvc/CppReact.vcxproj.filters b/project/msvc/CppReact.vcxproj.filters index d87af090..040e8acc 100644 --- a/project/msvc/CppReact.vcxproj.filters +++ b/project/msvc/CppReact.vcxproj.filters @@ -39,9 +39,6 @@ Header Files - - Header Files - Header Files\detail @@ -60,9 +57,6 @@ Header Files\detail - - Header Files\detail - Header Files @@ -81,6 +75,12 @@ Header Files\common + + Header Files\detail + + + Header Files + diff --git a/project/msvc/CppReactTest.vcxproj b/project/msvc/CppReactTest.vcxproj index eccef6a3..7516767f 100644 --- a/project/msvc/CppReactTest.vcxproj +++ b/project/msvc/CppReactTest.vcxproj @@ -168,8 +168,8 @@ - - + + diff --git a/project/msvc/CppReactTest.vcxproj.filters b/project/msvc/CppReactTest.vcxproj.filters index a6f9919a..6004eeed 100644 --- a/project/msvc/CppReactTest.vcxproj.filters +++ b/project/msvc/CppReactTest.vcxproj.filters @@ -24,19 +24,19 @@ Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files diff --git a/src/detail/graph_impl.cpp b/src/detail/graph_impl.cpp index 8dc4be9a..c6ceb6be 100644 --- a/src/detail/graph_impl.cpp +++ b/src/detail/graph_impl.cpp @@ -54,9 +54,17 @@ void ReactGraph::DetachNode(NodeId nodeId, NodeId parentId) successors.erase(std::find(successors.begin(), successors.end(), nodeId)); } -void ReactGraph::PushDependency(SyncPoint::Dependency dep) +void ReactGraph::AddSyncPointDependency(SyncPoint::Dependency dep, bool syncLinked) { - curDependencies_.push_back(std::move(dep)); + if (syncLinked) + linkDependencies_.push_back(std::move(dep)); + else + localDependencies_.push_back(std::move(dep)); +} + +void ReactGraph::AllowLinkedTransactionMerging(bool allowMerging) +{ + allowLinkedTransactionMerging_ = true; } void ReactGraph::Propagate() @@ -115,21 +123,35 @@ void ReactGraph::Propagate() for (IReactNode* nodePtr : changedNodes_) nodePtr->Clear(); changedNodes_.clear(); + + // Clean link state. + scheduledLinkOutputs_.clear(); + localDependencies_.clear(); + linkDependencies_.clear(); + allowLinkedTransactionMerging_ = false; } void ReactGraph::UpdateLinkNodes() { + TransactionFlags flags = TransactionFlags::none; + + if (! linkDependencies_.empty()) + flags |= TransactionFlags::sync_linked; + + if (allowLinkedTransactionMerging_) + flags |= TransactionFlags::allow_merging; + + SyncPoint::Dependency dep{ begin(linkDependencies_), end(linkDependencies_) }; + for (auto& e : scheduledLinkOutputs_) { - e.first->EnqueueTransaction(TransactionFlags::none, + e.first->EnqueueTransaction( [inputs = std::move(e.second)] { for (auto& callback : inputs) callback(); - }); + }, dep, flags); } - - scheduledLinkOutputs_.clear(); } void ReactGraph::ScheduleSuccessors(NodeData& node) @@ -197,7 +219,10 @@ size_t TransactionQueue::ProcessNextBatch() { StoredTransaction curTransaction; size_t popCount = 0; + bool canMerge = false; + bool syncLinked = false; + bool skipPop = false; bool isDone = false; @@ -210,6 +235,8 @@ size_t TransactionQueue::ProcessNextBatch() return popCount; canMerge = IsBitmaskSet(curTransaction.flags, TransactionFlags::allow_merging); + syncLinked = IsBitmaskSet(curTransaction.flags, TransactionFlags::sync_linked); + ++popCount; } else @@ -220,16 +247,21 @@ size_t TransactionQueue::ProcessNextBatch() graph_.DoTransaction([&] { curTransaction.func(); + graph_.AddSyncPointDependency(std::move(curTransaction.dep), syncLinked); if (canMerge) { - // Inner loop. Mergeable transactions are merged + graph_.AllowLinkedTransactionMerging(true); + + // Pull in additional mergeable transactions. for (;;) { - if (transactions_.try_pop(curTransaction)) + if (!transactions_.try_pop(curTransaction)) return; canMerge = IsBitmaskSet(curTransaction.flags, TransactionFlags::allow_merging); + syncLinked = IsBitmaskSet(curTransaction.flags, TransactionFlags::sync_linked); + ++popCount; if (!canMerge) @@ -239,6 +271,7 @@ size_t TransactionQueue::ProcessNextBatch() } curTransaction.func(); + graph_.AddSyncPointDependency(std::move(curTransaction.dep), syncLinked); } } }); diff --git a/tests/src/SignalTest.cpp b/tests/src/SignalTest.cpp deleted file mode 100644 index a34b7f98..00000000 --- a/tests/src/SignalTest.cpp +++ /dev/null @@ -1,11 +0,0 @@ - -// Copyright Sebastian Jeckel 2017. -// 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) - - -/////////////////////////////////////////////////////////////////////////////////////////////////// -namespace { - -} // ~namespace \ No newline at end of file diff --git a/tests/src/TransactionTest.cpp b/tests/src/TransactionTest.cpp deleted file mode 100644 index 6054092a..00000000 --- a/tests/src/TransactionTest.cpp +++ /dev/null @@ -1,12 +0,0 @@ - -// Copyright Sebastian Jeckel 2017. -// 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) - - -/////////////////////////////////////////////////////////////////////////////////////////////////// -namespace { - - -} // ~namespace \ No newline at end of file diff --git a/tests/src/common_tests.cpp b/tests/src/common_tests.cpp index 0bd5b6dc..8a78457a 100644 --- a/tests/src/common_tests.cpp +++ b/tests/src/common_tests.cpp @@ -15,6 +15,36 @@ using namespace react; /////////////////////////////////////////////////////////////////////////////////////////////////// +TEST(SyncPointTest, DependencyCreation) +{ + SyncPoint sp; + + { + SyncPoint::Dependency dep1(sp); + SyncPoint::Dependency dep2(sp); + SyncPoint::Dependency dep3(sp); + + std::vector deps1 = { dep1, dep2, dep3 }; + std::vector deps2 = { dep1 }; + + SyncPoint::Dependency dep4( begin(deps1), end(deps1) ); + + + SyncPoint::Dependency dep5; + + dep5 = std::move(dep4); + + SyncPoint::Dependency dep6; + dep6 = dep5; + SyncPoint::Dependency dep7( dep6 ); + + SyncPoint::Dependency dep8( begin(deps2), end(deps2) ); + } + + bool done = sp.WaitFor(std::chrono::milliseconds(1)); + EXPECT_EQ(true, done); +} + TEST(SyncPointTest, SingleWait) { SyncPoint sp; @@ -29,7 +59,6 @@ TEST(SyncPointTest, SingleWait) output = 1; }); - sp.Wait(); EXPECT_EQ(1, output); diff --git a/tests/src/event_tests.cpp b/tests/src/event_tests.cpp index 4204a466..31565b87 100644 --- a/tests/src/event_tests.cpp +++ b/tests/src/event_tests.cpp @@ -80,7 +80,7 @@ TEST(EventTest, BasicOutput) EXPECT_EQ(3, output); } -TEST(EventTest, EventSlots) +TEST(EventTest, Slots) { Group g; @@ -144,7 +144,7 @@ TEST(EventTest, EventSlots) EXPECT_EQ(4, turns); } -TEST(EventTest, EventTransactions) +TEST(EventTest, Transactions) { Group g; @@ -174,7 +174,7 @@ TEST(EventTest, EventTransactions) EXPECT_EQ(1, turns); } -TEST(EventTest, ExplicitEventLinks) +TEST(EventTest, Links) { Group g1; Group g2; diff --git a/tests/src/state_tests.cpp b/tests/src/state_tests.cpp new file mode 100644 index 00000000..7cca28db --- /dev/null +++ b/tests/src/state_tests.cpp @@ -0,0 +1,262 @@ + +// Copyright Sebastian Jeckel 2017. +// 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 "gtest/gtest.h" + +#include "react/state.h" +#include "react/observer.h" + +#include +#include + +using namespace react; + +TEST(StateTest, Construction) +{ + Group g; + + // State variable + { + StateVar t1( g, 0 ); + StateVar t2( t1 ); + StateVar t3( std::move(t1) ); + + StateVar ref1( t2 ); + State ref2( t3 ); + + EXPECT_TRUE(ref1 == ref2); + } + + // State slot + { + StateVar t0( g, 0 ); + + StateSlot t1( g, t0 ); + StateSlot t2( t1 ); + StateSlot t3( std::move(t1) ); + + StateSlot ref1( t2 ); + State ref2( t3 ); + + EXPECT_TRUE(ref1 == ref2); + } + + // State link + { + StateVar t0( g, 0 ); + + StateSlot s1( g, t0 ); + + StateLink t1( g, s1 ); + StateLink t2( t1 ); + StateLink t3( std::move(t1) ); + + StateLink ref1( t2 ); + State ref2( t3 ); + + EXPECT_TRUE(ref1 == ref2); + } +} + +TEST(StateTest, BasicOutput) +{ + Group g; + + StateVar st( g ); + + int output = 0; + + Observer obs([&] (const auto& v) + { + output += v; + }, st); + + EXPECT_EQ(0, output); + + st.Set(1); + EXPECT_EQ(1, output); + + st.Set(2); + EXPECT_EQ(3, output); +} + +TEST(StateTest, Slots) +{ + Group g; + + StateVar st1( g ); + StateVar st2( g ); + + StateSlot slot( g, st1 ); + + int output = 0; + int turns = 0; + + Observer obs([&] (const auto& v) + { + ++turns; + output += v; + }, slot); + + EXPECT_EQ(0, output); + EXPECT_EQ(1, turns); + + slot.Set(st1); + st1.Set(5); + st2.Set(2); + + EXPECT_EQ(5, output); + EXPECT_EQ(2, turns); + + output = 0; + + slot.Set(st2); + st1.Set(5); + st2.Set(2); + + EXPECT_EQ(2, output); + EXPECT_EQ(3, turns); +} + +TEST(StateTest, Transactions) +{ + Group g; + + StateVar st( g, 1 ); + + int output = 0; + int turns = 0; + + Observer obs([&] (const auto& v) + { + ++turns; + output += v; + }, st); + + EXPECT_EQ(1, output); + + g.DoTransaction([&] + { + st.Set(1); + st.Set(2); + st.Set(3); + st.Set(4); + }); + + EXPECT_EQ(5, output); + EXPECT_EQ(2, turns); +} + +TEST(StateTest, Links) +{ + Group g1; + Group g2; + Group g3; + + StateVar st1( g1, 1 ); + StateVar st2( g2, 2 ); + StateVar st3( g3, 3 ); + + StateSlot slot( g1, st1 ); + + int output = 0; + int turns = 0; + + Observer obs([&] (const auto& v) + { + ++turns; + output = v; + }, slot); + + EXPECT_EQ(1, turns); + st1.Set(10); + EXPECT_EQ(10, output); + EXPECT_EQ(2, turns); + + // Explicit link + StateLink lnk2( g1, st2 ); + slot.Set(lnk2); + std::this_thread::sleep_for(std::chrono::seconds(1)); + EXPECT_EQ(2, output); + EXPECT_EQ(3, turns); + + st2.Set(20); + std::this_thread::sleep_for(std::chrono::seconds(1)); + EXPECT_EQ(20, output); + EXPECT_EQ(4, turns); + + // Implicit link + slot.Set(st3); + std::this_thread::sleep_for(std::chrono::seconds(1)); + EXPECT_EQ(3, output); + EXPECT_EQ(5, turns); + + st3.Set(30); + std::this_thread::sleep_for(std::chrono::seconds(1)); + EXPECT_EQ(30, output); + EXPECT_EQ(6, turns); + + std::this_thread::sleep_for(std::chrono::seconds(1)); +} + +template +static T Sum2(T a, T b) +{ + return a + b; +} + +template +static T Sum3(T a, T b, T c) +{ + return a + b + c; +} + +TEST(StateTest, StateCombination) +{ + Group g; + + StateVar a( g, 0 ); + StateVar b( g, 0 ); + StateVar c( g, 0 ); + + State s1(Sum2, a, b); + + State x(Sum2, s1, c); + State y(Sum3, a, b, c); + + int output1 = 0; + int output2 = 0; + int turns1 = 0; + int turns2 = 0; + + Observer obs1([&] (int v) + { + ++turns1; + output1 = v; + }, x); + + EXPECT_EQ(0, output1); + EXPECT_EQ(1, turns1); + + Observer obs2([&] (int v) + { + ++turns2; + output2 = v; + }, y); + + EXPECT_EQ(0, output2); + EXPECT_EQ(1, turns2); + + a.Set(1); + b.Set(1); + c.Set(1); + + EXPECT_EQ(3, output1); + EXPECT_EQ(4, turns1); + + EXPECT_EQ(3, output2); + EXPECT_EQ(4, turns2); +} \ No newline at end of file diff --git a/tests/src/transaction_tests.cpp b/tests/src/transaction_tests.cpp new file mode 100644 index 00000000..33812c75 --- /dev/null +++ b/tests/src/transaction_tests.cpp @@ -0,0 +1,220 @@ + +// Copyright Sebastian Jeckel 2017. +// 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 "gtest/gtest.h" + +#include "react/event.h" +#include "react/observer.h" + +#include +#include + +using namespace react; + +TEST(TransactionTests, Merging) +{ + Group g; + + EventSource evt( g ); + + int output = 0; + int turns = 0; + + Observer obs([&] (const auto& events) + { + ++turns; + for (int e : events) + output += e; + }, evt); + + // This transaction blocks the queue for one second. + g.EnqueueTransaction([&] + { + std::this_thread::sleep_for(std::chrono::seconds(1)); + }); + + SyncPoint sp; + + // Enqueue 3 more transaction while the queue is blocked. + // They should be merged together as a result. + g.EnqueueTransaction([&] + { + evt.Emit(1); + evt.Emit(2); + }, sp, TransactionFlags::allow_merging); + + g.EnqueueTransaction([&] + { + evt.Emit(3); + evt.Emit(4); + }, sp, TransactionFlags::allow_merging); + + g.EnqueueTransaction([&] + { + evt.Emit(5); + evt.Emit(6); + }, sp, TransactionFlags::allow_merging); + + bool done = sp.WaitFor(std::chrono::seconds(3)); + EXPECT_EQ(true, done); + + // They have been merged, there should only be a single turn. + EXPECT_EQ(1, turns); + + // None of the emitted values have been lost. + EXPECT_EQ(21, output); +} + +TEST(TransactionTests, LinkedSync) +{ + // Three groups. Each has one event with an observer attached. + // The last observer adds a little delay. + + Group g1; + Group g2; + Group g3; + + EventSource evt1( g1 ); + + int output1 = 0; + int turns1 = 0; + + Observer obs1([&] (const auto& events) + { + ++turns1; + for (int e : events) + output1 += e; + }, evt1); + + Event evt2 = Filter(g2, [] (const auto&) { return true; }, evt1); + + int output2 = 0; + int turns2 = 0; + + Observer obs2([&] (const auto& events) + { + ++turns2; + for (int e : events) + output2 += e; + }, evt2); + + Event evt3 = Filter(g3, [] (const auto&) { return true; }, evt2); + + int output3 = 0; + int turns3 = 0; + + Observer obs3([&] (const auto& events) + { + std::this_thread::sleep_for(std::chrono::seconds(1)); + + ++turns3; + for (int e : events) + output3 += e; + }, evt3); + + SyncPoint sp; + + // Enqueue a transaction that waits on linked nodes. + g1.EnqueueTransaction([&] + { + evt1.Emit(1); + evt1.Emit(2); + }, sp, TransactionFlags::sync_linked); + + // We should wait for all three observers. + bool done = sp.WaitFor(std::chrono::seconds(3)); + + EXPECT_EQ(true, done); + + EXPECT_EQ(1, turns1); + EXPECT_EQ(1, turns2); + EXPECT_EQ(1, turns3); + + EXPECT_EQ(3, output1); + EXPECT_EQ(3, output2); + EXPECT_EQ(3, output3); +} + +TEST(TransactionTests, LinkedSyncMerging) +{ + // Two groups. Each has one event with an observer attached. + // The last observer adds a little delay. + + Group g1; + Group g2; + + EventSource evt1( g1 ); + + int output1 = 0; + int turns1 = 0; + + Observer obs1([&] (const auto& events) + { + ++turns1; + for (int e : events) + output1 += e; + }, evt1); + + Event evt2 = Filter(g2, [] (const auto&) { return true; }, evt1); + + int output2 = 0; + int turns2 = 0; + + Observer obs2([&] (const auto& events) + { + std::this_thread::sleep_for(std::chrono::seconds(1)); + + ++turns2; + for (int e : events) + output2 += e; + }, evt2); + + SyncPoint sp1; + SyncPoint sp2; + + // This transaction blocks the queue for one second. + g1.EnqueueTransaction([&] + { + std::this_thread::sleep_for(std::chrono::seconds(1)); + }); + + // Two more transactions are enqueued using two different sync points. + // The first one should only sync on obs1, not on linked nodes. + g1.EnqueueTransaction([&] + { + evt1.Emit(1); + evt1.Emit(2); + }, sp1, TransactionFlags::allow_merging); + + // The second one should sync on obs2 as well. + g1.EnqueueTransaction([&] + { + evt1.Emit(3); + evt1.Emit(4); + }, sp2, TransactionFlags::allow_merging | TransactionFlags::sync_linked); + + // Should be done after obs1 is done with both transactions (because they have been merged). + bool done = sp1.WaitFor(std::chrono::seconds(5)); + + EXPECT_EQ(true, done); + + EXPECT_EQ(1, turns1); + EXPECT_EQ(0, turns2); + + EXPECT_EQ(10, output1); + EXPECT_EQ(0, output2); + + // Should be done after obs2 is done. + done = sp2.WaitFor(std::chrono::seconds(5)); + + EXPECT_EQ(true, done); + + EXPECT_EQ(1, turns1); + EXPECT_EQ(1, turns2); + + EXPECT_EQ(10, output1); + EXPECT_EQ(10, output2); +} \ No newline at end of file From 238e09e0e73f58290487b43d481cb6592b49b8f3 Mon Sep 17 00:00:00 2001 From: schlangster Date: Tue, 24 Oct 2017 23:51:13 +0200 Subject: [PATCH 54/75] EventLinkNode cleanup. --- include/react/detail/event_nodes.h | 41 +++++++++++++----------------- 1 file changed, 17 insertions(+), 24 deletions(-) diff --git a/include/react/detail/event_nodes.h b/include/react/detail/event_nodes.h index f422a903..dfec7020 100644 --- a/include/react/detail/event_nodes.h +++ b/include/react/detail/event_nodes.h @@ -424,13 +424,23 @@ class EventLinkNode : public EventNode public: EventLinkNode(const Group& group, const Event& dep) : EventLinkNode::EventNode( group ), - linkOutput_( dep ) + dep_( dep ), + srcGroup_( dep.GetGroup() ) { this->RegisterMe(NodeCategory::input); + + auto& srcGraphPtr = GetInternals(srcGroup_).GetGraphPtr(); + outputNodeId_ = srcGraphPtr->RegisterNode(&linkOutput_, NodeCategory::linkoutput); + + srcGraphPtr->AttachNode(outputNodeId_, GetInternals(dep).GetNodeId()); } ~EventLinkNode() { + auto& srcGraphPtr = GetInternals(srcGroup_).GetGraphPtr(); + srcGraphPtr->DetachNode(outputNodeId_, GetInternals(dep_).GetNodeId()); + srcGraphPtr->UnregisterNode(outputNodeId_); + auto& linkCache = GetGraphPtr()->GetLinkCache(); linkCache.Erase(this); @@ -449,23 +459,6 @@ class EventLinkNode : public EventNode private: struct VirtualOutputNode : public IReactNode { - VirtualOutputNode(const Event& depIn) : - parent( ), - dep( depIn ), - srcGroup( depIn.GetGroup() ) - { - auto& srcGraphPtr = GetInternals(srcGroup).GetGraphPtr(); - nodeId = srcGraphPtr->RegisterNode(this, NodeCategory::linkoutput); - srcGraphPtr->AttachNode(nodeId, GetInternals(dep).GetNodeId()); - } - - ~VirtualOutputNode() - { - auto& srcGraphPtr = GetInternals(srcGroup).GetGraphPtr(); - srcGraphPtr->DetachNode(nodeId, GetInternals(dep).GetNodeId()); - srcGraphPtr->UnregisterNode(nodeId); - } - virtual UpdateResult Update(TurnId turnId) noexcept override { return UpdateResult::changed; } @@ -475,7 +468,7 @@ class EventLinkNode : public EventNode { auto* rawPtr = p->GetGraphPtr().get(); output[rawPtr].push_back( - [storedParent = std::move(p), storedEvents = GetInternals(dep).Events()] () mutable + [storedParent = std::move(p), storedEvents = GetInternals(p->dep_).Events()] () mutable { NodeId nodeId = storedParent->GetNodeId(); auto& graphPtr = storedParent->GetGraphPtr(); @@ -489,13 +482,13 @@ class EventLinkNode : public EventNode } } - std::weak_ptr parent; - - NodeId nodeId; - Event dep; - Group srcGroup; + std::weak_ptr parent; }; + Event dep_; + Group srcGroup_; + NodeId outputNodeId_; + VirtualOutputNode linkOutput_; }; From 5a9912825d442d5d3ffd0fc09a79408fc6f75d60 Mon Sep 17 00:00:00 2001 From: schlangster Date: Tue, 24 Oct 2017 23:57:06 +0200 Subject: [PATCH 55/75] Renamed and deleted files. --- include/react/{Algorithm.h => algorithm.h} | 0 include/react/{API.h => api.h} | 0 include/react/common/RefCounting.h | 112 ------- include/react/common/SourceIdSet.h | 135 --------- include/react/common/Timing.h | 201 ------------- include/react/common/TopoQueue.h | 332 --------------------- include/react/common/Types.h | 31 -- include/react/common/expected.h | 218 -------------- include/react/common/optional.h | 70 ----- include/react/common/owned_ptr.h | 18 -- include/react/detail/{Defs.h => defs.h} | 0 include/react/{Event.h => event.h} | 0 include/react/{Group.h => group.h} | 0 include/react/{Observer.h => observer.h} | 0 14 files changed, 1117 deletions(-) rename include/react/{Algorithm.h => algorithm.h} (100%) rename include/react/{API.h => api.h} (100%) delete mode 100644 include/react/common/RefCounting.h delete mode 100644 include/react/common/SourceIdSet.h delete mode 100644 include/react/common/Timing.h delete mode 100644 include/react/common/TopoQueue.h delete mode 100644 include/react/common/Types.h delete mode 100644 include/react/common/expected.h delete mode 100644 include/react/common/optional.h delete mode 100644 include/react/common/owned_ptr.h rename include/react/detail/{Defs.h => defs.h} (100%) rename include/react/{Event.h => event.h} (100%) rename include/react/{Group.h => group.h} (100%) rename include/react/{Observer.h => observer.h} (100%) diff --git a/include/react/Algorithm.h b/include/react/algorithm.h similarity index 100% rename from include/react/Algorithm.h rename to include/react/algorithm.h diff --git a/include/react/API.h b/include/react/api.h similarity index 100% rename from include/react/API.h rename to include/react/api.h diff --git a/include/react/common/RefCounting.h b/include/react/common/RefCounting.h deleted file mode 100644 index 37bb5e68..00000000 --- a/include/react/common/RefCounting.h +++ /dev/null @@ -1,112 +0,0 @@ - -// Copyright Sebastian Jeckel 2017. -// 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) - -#ifndef REACT_COMMON_REF_COUNTING_H_INCLUDED -#define REACT_COMMON_REF_COUNTING_H_INCLUDED - -#pragma once - -#include "react/detail/defs.h" - -#include -#include - -/***************************************/ REACT_IMPL_BEGIN /**************************************/ - -// A non-exception-safe pointer wrapper with conditional intrusive ref counting. -template -class IntrusiveRefCountingPtr -{ - enum - { - tag_ref_counted = 0x1 - }; - -public: - IntrusiveRefCountingPtr() : - ptrData_( reinterpret_cast(nullptr) ) - {} - - IntrusiveRefCountingPtr(T* ptr) : - ptrData_( reinterpret_cast(ptr) ) - { - if (ptr != nullptr && ptr->IsRefCounted()) - { - ptr->IncRefCount(); - ptrData_ |= tag_ref_counted; - } - } - - IntrusiveRefCountingPtr(const IntrusiveRefCountingPtr& other) : - ptrData_( other.ptrData_ ) - { - if (isValidRefCountedPtr()) - Get()->IncRefCount(); - } - - IntrusiveRefCountingPtr(IntrusiveRefCountingPtr&& other) : - ptrData_( other.ptrData_ ) - { - other.ptrData_ = reinterpret_cast(nullptr); - } - - ~IntrusiveRefCountingPtr() - { - if (isValidRefCountedPtr()) - Get()->DecRefCount(); - } - - IntrusiveRefCountingPtr& operator=(const IntrusiveRefCountingPtr& other) - { - if (this != &other) - { - if (other.isValidRefCountedPtr()) - other.Get()->IncRefCount(); - - if (isValidRefCountedPtr()) - Get()->DecRefCount(); - - ptrData_ = other.ptrData_; - } - - return *this; - } - - IntrusiveRefCountingPtr& operator=(IntrusiveRefCountingPtr&& other) - { - if (this != &other) - { - if (isValidRefCountedPtr()) - Get()->DecRefCount(); - - ptrData_ = other.ptrData_; - other.ptrData_ = reinterpret_cast(nullptr); - } - - return *this; - } - - T* Get() const { return reinterpret_cast(ptrData_ & ~tag_ref_counted); } - - T& operator*() const { return *Get(); } - T* operator->() const { return Get(); } - - bool operator==(const IntrusiveRefCountingPtr& other) const { return Get() == other.Get(); } - bool operator!=(const IntrusiveRefCountingPtr& other) const { return !(*this == other); } - -private: - bool isValidRefCountedPtr() const - { - return ptrData_ != reinterpret_cast(nullptr) - && (ptrData_ & tag_ref_counted) != 0; - } - - uintptr_t ptrData_; -}; - -/****************************************/ REACT_IMPL_END /***************************************/ - -#endif // REACT_COMMON_REF_COUNTING_H_INCLUDED \ No newline at end of file diff --git a/include/react/common/SourceIdSet.h b/include/react/common/SourceIdSet.h deleted file mode 100644 index 902a39aa..00000000 --- a/include/react/common/SourceIdSet.h +++ /dev/null @@ -1,135 +0,0 @@ - -// Copyright Sebastian Jeckel 2017. -// 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) - -#ifndef REACT_COMMON_SOURCEIDSET_H_INCLUDED -#define REACT_COMMON_SOURCEIDSET_H_INCLUDED - -#pragma once - -#include "react/detail/defs.h" - -#include -#include - -#include "tbb/queuing_mutex.h" - -/***************************************/ REACT_IMPL_BEGIN /**************************************/ - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// SourceIdSet -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -class SourceIdSet -{ -private: - using MutexT = tbb::queuing_mutex; - using DataT = std::vector; - -public: - void Insert(const T& e) - { - MutexT::scoped_lock lock(mutex_); - - data_.push_back(e); - - isSorted_ = false; - } - - void Insert(SourceIdSet& other) - { - MutexT::scoped_lock myLock(mutex_); - MutexT::scoped_lock otherLock(other.mutex_); - - sort(); - other.sort(); - - auto l = data_.begin(); - auto r = data_.end(); - auto offset = std::distance(l,r); - - // For each element in other, check if it's already contained in this - // if not, add it - for (const auto& e : other.data_) - { - l = std::lower_bound(l, r, e); - - // Already in the set? - if (l < r && *l == e) - continue; - - auto d = std::distance(data_.begin(), l); - - data_.push_back(e); - - // push_back invalidates iterators - l = data_.begin() + d; - r = data_.begin() + offset; - } - - std::inplace_merge(data_.begin(), data_.begin() + offset, data_.end()); - } - - void Erase(const T& e) - { - MutexT::scoped_lock lock(mutex_); - - data_.erase(std::find(data_.begin(), data_.end(), e)); - } - - void Clear() - { - MutexT::scoped_lock lock(mutex_); - - data_.clear(); - isSorted_ = true; - } - - bool IntersectsWith(SourceIdSet& other) - { - MutexT::scoped_lock myLock(mutex_); - MutexT::scoped_lock otherLock(other.mutex_); - - sort(); - other.sort(); - - auto l1 = data_.begin(); - const auto r1 = data_.end(); - - auto l2 = other.data_.begin(); - const auto r2 = other.data_.end(); - - // Is intersection of turn sourceIds and node sourceIds non-empty? - while (l1 != r1 && l2 != r2) - { - if (*l1 < *l2) - l1++; - else if (*l2 < *l1) - l2++; - // Equals => Intersect - else - return true; - } - return false; - } - -private: - MutexT mutex_; - DataT data_; - bool isSorted_ = false; - - void sort() - { - if (isSorted_) - return; - - std::sort(data_.begin(), data_.end()); - isSorted_ = true; - } -}; - -/****************************************/ REACT_IMPL_END /***************************************/ - -#endif // REACT_COMMON_SOURCEIDSET_H_INCLUDED \ No newline at end of file diff --git a/include/react/common/Timing.h b/include/react/common/Timing.h deleted file mode 100644 index 7d6c81ac..00000000 --- a/include/react/common/Timing.h +++ /dev/null @@ -1,201 +0,0 @@ - -// Copyright Sebastian Jeckel 2017. -// 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) - -#ifndef REACT_COMMON_TIMING_H_INCLUDED -#define REACT_COMMON_TIMING_H_INCLUDED - -#pragma once - -#include "react/detail/defs.h" - -#include - -#if _WIN32 || _WIN64 - #define REACT_FIXME_CUSTOM_TIMER 1 -#else - #define REACT_FIXME_CUSTOM_TIMER 0 -#endif - -#if REACT_FIXME_CUSTOM_TIMER - #include -#else - #include -#endif - -/***************************************/ REACT_IMPL_BEGIN /**************************************/ - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// GetPerformanceFrequency -/////////////////////////////////////////////////////////////////////////////////////////////////// -// Todo: Initialization not thread-safe -#if REACT_FIXME_CUSTOM_TIMER -inline const LARGE_INTEGER& GetPerformanceFrequency() -{ - static bool init = false; - static LARGE_INTEGER frequency; - - if (init == false) - { - QueryPerformanceFrequency(&frequency); - init = true; - } - - return frequency; -} -#endif - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// ConditionalTimer -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - long long threshold, - bool is_enabled -> -class ConditionalTimer -{ -public: - class ScopedTimer - { - public: - // Note: - // Count is passed by ref so it can be set later if it's not known at time of creation - ScopedTimer(const ConditionalTimer&, const size_t& count); - }; - - void Reset(); - void ForceThresholdExceeded(bool isExceeded); - bool IsThresholdExceeded() const; -}; - -// Disabled -template -< - long long threshold -> -class ConditionalTimer -{ -public: - // Defines scoped timer that does nothing - class ScopedTimer - { - public: - ScopedTimer(const ConditionalTimer&, const size_t& count) {} - }; - - void Reset() {} - void ForceThresholdExceeded(bool isExceeded) {} - bool IsThresholdExceeded() const { return false; } -}; - -// Enabled -template -< - long long threshold -> -class ConditionalTimer -{ -public: -#if REACT_FIXME_CUSTOM_TIMER - using TimestampT = LARGE_INTEGER; -#else - using ClockT = std::chrono::high_resolution_clock; - using TimestampT = std::chrono::time_point; -#endif - - class ScopedTimer - { - public: - ScopedTimer(ConditionalTimer& parent, const size_t& count) : - parent_( parent ), - count_( count ) - { - if (!parent_.shouldMeasure_) - return; - - startMeasure(); - } - - ~ScopedTimer() - { - if (!parent_.shouldMeasure_) - return; - - parent_.shouldMeasure_ = false; - - endMeasure(); - } - - private: - void startMeasure() - { - startTime_ = now(); - } - - void endMeasure() - { -#if REACT_FIXME_CUSTOM_TIMER - TimestampT endTime = now(); - - LARGE_INTEGER durationUS; - - durationUS.QuadPart = endTime.QuadPart - startTime_.QuadPart; - durationUS.QuadPart *= 1000000; - durationUS.QuadPart /= GetPerformanceFrequency().QuadPart; - - parent_.isThresholdExceeded_ = (durationUS.QuadPart - (threshold * count_)) > 0; -#else - using std::chrono::duration_cast; - using std::chrono::microseconds; - - parent_.isThresholdExceeded_ = - duration_cast(now() - startTime_).count() > (threshold * count_); -#endif - } - - ConditionalTimer& parent_; - TimestampT startTime_; - const size_t& count_; - }; - - static TimestampT now() - { -#if REACT_FIXME_CUSTOM_TIMER - TimestampT result; - QueryPerformanceCounter(&result); - return result; -#else - return ClockT::now(); -#endif - } - - void Reset() - { - shouldMeasure_ = true; - isThresholdExceeded_ = false; - } - - void ForceThresholdExceeded(bool isExceeded) - { - shouldMeasure_ = false; - isThresholdExceeded_ = isExceeded; - } - - bool IsThresholdExceeded() const { return isThresholdExceeded_; } - -private: - // Only measure once - bool shouldMeasure_ = true; - - // Until we have measured, assume the threshold is exceeded. - // The cost of initially not parallelizing what should be parallelized is much higher - // than for the other way around. - bool isThresholdExceeded_ = true; -}; - -/****************************************/ REACT_IMPL_END /***************************************/ - -#endif // REACT_COMMON_TIMING_H_INCLUDED \ No newline at end of file diff --git a/include/react/common/TopoQueue.h b/include/react/common/TopoQueue.h deleted file mode 100644 index 2c3c4613..00000000 --- a/include/react/common/TopoQueue.h +++ /dev/null @@ -1,332 +0,0 @@ - -// Copyright Sebastian Jeckel 2017. -// 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) - -#ifndef REACT_COMMON_TOPOQUEUE_H_INCLUDED -#define REACT_COMMON_TOPOQUEUE_H_INCLUDED - -#pragma once - -#include "react/detail/defs.h" - -#include -#include -#include -#include -#include - -#include "tbb/enumerable_thread_specific.h" -#include "tbb/tbb_stddef.h" - -/***************************************/ REACT_IMPL_BEGIN /**************************************/ - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// TopoQueue - Sequential -/////////////////////////////////////////////////////////////////////////////////////////////////// - -template -int GetNodeLevel(const T& node) - { return node.level; } - -template -int GetNodeLevel(const T* node) - { return node->level; } - -template -class TopoQueue -{ -private: - struct Entry; - -public: - // Store the level as part of the entry for cheap comparisons - using QueueDataT = std::vector; - using NextDataT = std::vector; - - TopoQueue() = default; - TopoQueue(const TopoQueue&) = default; - - void Push(const T& value) - { - queueData_.emplace_back(value, GetNodeLevel(value)); - } - - bool FetchNext() - { - // Throw away previous values - nextData_.clear(); - - // Find min level of nodes in queue data - minLevel_ = (std::numeric_limits::max)(); - for (const auto& e : queueData_) - if (minLevel_ > e.Level) - minLevel_ = e.Level; - - // Swap entries with min level to the end - auto p = std::partition( - queueData_.begin(), - queueData_.end(), - [minLevel_] (const Entry& e) { return minLevel_ != e.level; }); - - // Reserve once to avoid multiple re-allocations - nextData_.reserve(std::distance(p, queueData_.end())); - - // Move min level values to next data - for (auto it = p; it != queueData_.end(); ++it) - nextData_.push_back(std::move(it->Value)); - - // Truncate moved entries - queueData_.resize(std::distance(queueData_.begin(), p)); - - return !nextData_.empty(); - } - - const NextDataT& NextValues() const { return nextData_; } - -private: - struct Entry - { - Entry() = default; - Entry(const Entry&) = default; - - Entry(const T& value, int level) : Value( value ), Level( level ) {} - - T Value; - int Level; - }; - - struct LevelCompFunctor - { - LevelCompFunctor(int level) : Level( level ) {} - - bool operator()(const Entry& e) const { return e.Level != Level; } - - const int Level; - }; - - NextDataT nextData_; - QueueDataT queueData_; - - TLevelFunc levelFunc_; - - int minLevel_ = (std::numeric_limits::max)(); -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// WeightedRange - Implements tbb range concept -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename TIt, - uint grain_size -> -class WeightedRange -{ -public: - using const_iterator = TIt; - using ValueT = typename TIt::value_type; - - WeightedRange() = default; - WeightedRange(const WeightedRange&) = default; - - WeightedRange(const TIt& a, const TIt& b, uint weight) : - begin_( a ), - end_( b ), - weight_( weight ) - {} - - WeightedRange(WeightedRange& source, tbb::split) - { - uint sum = 0; - TIt p = source.begin_; - while (p != source.end_) - { - // Note: assuming a pair with weight as second until more flexibility is needed - sum += p->second; - ++p; - if (sum >= grain_size) - break; - } - - // New [p,b) - begin_ = p; - end_ = source.end_; - weight_ = source.weight_ - sum; - - // Source [a,p) - source.end_ = p; - source.weight_ = sum; - } - - // tbb range interface - bool empty() const { return !(Size() > 0); } - bool is_divisible() const { return weight_ > grain_size && Size() > 1; } - - // iteration interface - const_iterator begin() const { return begin_; } - const_iterator end() const { return end_; } - - size_t Size() const { return end_ - begin_; } - uint Weight() const { return weight_; } - -private: - TIt begin_; - TIt end_; - uint weight_ = 0; -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// ConcurrentTopoQueue -/// Usage based on two phases: -/// 1. Multiple threads push nodes to the queue concurrently. -/// 2. FetchNext() prepares all nodes of the next level in NextNodes(). -/// The previous contents of NextNodes() are automatically cleared. -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -< typename T, - uint grain_size, - typename TLevelFunc, - typename TWeightFunc -> -class ConcurrentTopoQueue -{ -private: - struct Entry; - -public: - using QueueDataT = std::vector; - using NextDataT = std::vector>; - using NextRangeT = WeightedRange; - - ConcurrentTopoQueue() = default; - ConcurrentTopoQueue(const ConcurrentTopoQueue&) = default; - - template - ConcurrentTopoQueue(FIn1&& levelFunc, FIn2&& weightFunc) : - levelFunc_( std::forward(levelFunc) ), - weightFunc_( std::forward(weightFunc) ) - {} - - void Push(const T& value) - { - auto& t = collectBuffer_.local(); - - auto level = levelFunc_(value); - auto weight = weightFunc_(value); - - t.Data.emplace_back(value,level,weight); - - t.Weight += weight; - - if (t.MinLevel > level) - t.MinLevel = level; - } - - bool FetchNext() - { - nextData_.clear(); - uint totalWeight = 0; - - // Determine current min level - minLevel_ = (std::numeric_limits::max)(); - for (const auto& buf : collectBuffer_) - if (minLevel_ > buf.MinLevel) - minLevel_ = buf.MinLevel; - - // For each thread local buffer... - for (auto& buf : collectBuffer_) - { - auto& v = buf.Data; - - // Swap min level nodes to end of v - auto p = std::partition( - v.begin(), - v.end(), - LevelCompFunctor{ minLevel_ }); - - // Reserve once to avoid multiple re-allocations - nextData_.reserve(std::distance(p, v.end())); - - // Move min level values to global next data - for (auto it = p; it != v.end(); ++it) - nextData_.emplace_back(std::move(it->Value), it->Weight); - - // Truncate remaining - v.resize(std::distance(v.begin(), p)); - - // Calc new min level and weight for this buffer - buf.MinLevel = (std::numeric_limits::max)(); - int oldWeight = buf.Weight; - buf.Weight = 0; - for (const auto& x : v) - { - buf.Weight += x.Weight; - - if (buf.MinLevel > x.Level) - buf.MinLevel = x.Level; - } - - // Add diff to nodes_ weight - totalWeight += oldWeight - buf.Weight; - } - - nextRange_ = NextRangeT{ nextData_.begin(), nextData_.end(), totalWeight }; - - // Found more nodes? - return !nextData_.empty(); - } - - const NextRangeT& NextRange() const - { - return nextRange_; - } - -private: - struct Entry - { - Entry() = default; - Entry(const Entry&) = default; - - Entry(const T& value, int level, uint weight) : - Value( value ), - Level( level ), - Weight( weight ) - {} - - T Value; - int Level; - uint Weight; - }; - - struct LevelCompFunctor - { - LevelCompFunctor(int level) : Level{ level } {} - - bool operator()(const Entry& e) const { return e.Level != Level; } - - const int Level; - }; - - struct ThreadLocalBuffer - { - QueueDataT Data; - int MinLevel = (std::numeric_limits::max)(); - uint Weight = 0; - }; - - int minLevel_ = (std::numeric_limits::max)(); - - NextDataT nextData_; - NextRangeT nextRange_; - - TLevelFunc levelFunc_; - TWeightFunc weightFunc_; - - tbb::enumerable_thread_specific collectBuffer_; -}; - -/****************************************/ REACT_IMPL_END /***************************************/ - -#endif // REACT_COMMON_TOPOQUEUE_H_INCLUDED \ No newline at end of file diff --git a/include/react/common/Types.h b/include/react/common/Types.h deleted file mode 100644 index 30a377fa..00000000 --- a/include/react/common/Types.h +++ /dev/null @@ -1,31 +0,0 @@ - -// Copyright Sebastian Jeckel 2017. -// 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) - -#ifndef REACT_COMMON_TYPES_H_INCLUDED -#define REACT_COMMON_TYPES_H_INCLUDED - -#pragma once - -#include "react/detail/defs.h" - -#include -#include - -/***************************************/ REACT_IMPL_BEGIN /**************************************/ - -using ObjectId = uintptr_t; - -template -ObjectId GetObjectId(const O& obj) -{ - return (ObjectId)&obj; -} - -using UpdateDurationT = std::chrono::duration; - -/****************************************/ REACT_IMPL_END /***************************************/ - -#endif // REACT_COMMON_TYPES_H_INCLUDED \ No newline at end of file diff --git a/include/react/common/expected.h b/include/react/common/expected.h deleted file mode 100644 index 5bdff539..00000000 --- a/include/react/common/expected.h +++ /dev/null @@ -1,218 +0,0 @@ - -// Copyright Sebastian Jeckel 2016. -// 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) - -#ifndef REACT_COMMON_EXPECTED_H_INCLUDED -#define REACT_COMMON_EXPECTED_H_INCLUDED - -#pragma once - -#include "react/detail/Defs.h" - -#include -#include -#include -#include - -/*****************************************/ REACT_BEGIN /*****************************************/ - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// IError -/////////////////////////////////////////////////////////////////////////////////////////////////// -class IErrorCause -{ -public: - virtual ~IErrorCause() = default; - - virtual std::string GetMessage() const = 0; - - virtual bool IsOfType(const char* typeId) const = 0; -}; - - -class AllocationError : public IErrorCause -{ -public: - static constexpr const char* type_id = "react::AllocationError"; - - virtual std::string GetMessage() const - { return "Allocation error."; } - - virtual bool IsOfType(const char* typeId) const - { return typeId == type_id; } -}; - - -class PreconditionError : public IErrorCause -{ -public: - static constexpr const char* type_id = "react::PreconditionError"; - - virtual std::string GetMessage() const - { return "Precondition error."; } - - virtual bool IsOfType(const char* typeId) const - { return typeId == type_id; } -}; - - -class PostconditionError : public IErrorCause -{ -public: - static constexpr const char* type_id = "react::PostconditionError"; - - virtual std::string GetMessage() const - { return "Postcondition error."; } - - virtual bool IsOfType(const char* typeId) const - { return typeId == type_id; } -}; - - -class MissingValueError : public IErrorCause -{ -public: - static constexpr const char* type_id = "react::MissingValueError"; - - virtual std::string GetMessage() const - { return "Missing value error."; } - - virtual bool IsOfType(const char* typeId) const - { return typeId == type_id; } -}; - - -class Error -{ -public: - template - < - typename T, - typename = std::enable_if_t> - > - Error(T cause) : - cause_(std::make_shared(std::move(cause))) - { } - - template - < - typename T, - typename = std::enable_if_t> - > - bool IsCause() const - { return cause_->IsOfType(T::type_id); } - - template - < - typename T, - typename = std::enable_if_t> - > - T* GetCause() const - { return static_cast(cause_.get()); } - - std::string GetMessage() const - { return cause_->GetMessage(); } - -private: - std::shared_ptr cause_; -}; - -static Error* GetErrorSentinel() - { return reinterpret_cast(0x1u); } - -struct ErrorDeleter -{ - void operator()(Error* p) const - { - if (p != GetErrorSentinel()) - delete p; - } -}; - -using UniqueErrorPtrType = std::unique_ptr; - - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Expected -/// -/// TODO: Optimize for different storage types to avoid branch in destructor. -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -class Expected -{ -public: - Expected() = delete; - - Expected(const Expected&) = delete; - - Expected& operator=(const Expected&) = delete; - - Expected(Expected&&) = default; - - Expected& operator=(Expected&&) = default; - - Expected(const T& value) : - error_( GetErrorSentinel() ) - { - ValueRef() = value; - } - - Expected(T&& value) : - error_( GetErrorSentinel() ) - { - ValueRef() = std::move(value); - } - - Expected(Error err) : - error_(new Error(std::move(err))) - { } - - Expected(UniqueErrorPtrType&& err) : - error_(std::move(err)) - { } - - ~Expected() - { - if (error_.get() == GetErrorSentinel()) - { - Destruct(); - } - } - - explicit operator bool() const - { - return error_.get() == GetErrorSentinel(); - } - - Error GetError() - { return *error_; } - -private: - const T& ValueRef() const - { return *reinterpret_cast(&valueStorage_); } - - T& ValueRef() - { return *reinterpret_cast(&valueStorage_); } - - void Destruct() - { reinterpret_cast(&valueStorage_)->~T(); } - - std::aligned_storage_t valueStorage_; - - std::unique_ptr error_; - - template - friend typename UniqueErrorPtrType UnwindExpected(Expected&& ex); -}; - -template -typename UniqueErrorPtrType UnwindExpected(Expected&& ex) -{ - return std::move(std::move(ex).error_); -} - -/******************************************/ REACT_END /******************************************/ - -#endif // REACT_COMMON_INDEXED_STORAGE_H_INCLUDED \ No newline at end of file diff --git a/include/react/common/optional.h b/include/react/common/optional.h deleted file mode 100644 index 3208c33b..00000000 --- a/include/react/common/optional.h +++ /dev/null @@ -1,70 +0,0 @@ - -// Copyright Sebastian Jeckel 2017. -// 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) - -#ifndef REACT_COMMON_OPTIONAL_H_INCLUDED -#define REACT_COMMON_OPTIONAL_H_INCLUDED - -#pragma once - -#include "react/detail/defs.h" - -#include -#include -#include - -struct NoValueType -{ - struct Tag {}; - - explicit constexpr NoValueType(Tag) - { } -}; - -constexpr NoValueType no_value{ NoValueType::Tag{ } }; - -/***************************************/ REACT_IMPL_BEGIN /**************************************/ - -template -class OptScalarStorage -{ -public: - OptScalarStorage() : hasValue_( false ) - { } - - OptScalarStorage(NoValueType) : hasValue_( false ) - { } - - OptScalarStorage& operator=(NoValueType) - { - hasValue_ = false; - return *this; - } - - OptScalarStorage(const OptScalarStorage&) = default; - - OptScalarStorage& operator=(const OptScalarStorage&) = default; - - bool HasValue() const - { return hasValue_; } - - const T& Value() const - { return value_; } - - T& Value() - { return value_; } - -private: - T value_; - bool hasValue_; -}; - -/****************************************/ REACT_IMPL_END /***************************************/ - -/*****************************************/ REACT_BEGIN /*****************************************/ - -/******************************************/ REACT_END /******************************************/ - -#endif // REACT_COMMON_OPTIONAL_H_INCLUDED \ No newline at end of file diff --git a/include/react/common/owned_ptr.h b/include/react/common/owned_ptr.h deleted file mode 100644 index f0d06bcb..00000000 --- a/include/react/common/owned_ptr.h +++ /dev/null @@ -1,18 +0,0 @@ - -// Copyright Sebastian Jeckel 2017. -// 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) - -#ifndef REACT_COMMON_OWNED_PTR_H_INCLUDED -#define REACT_COMMON_OWNED_PTR_H_INCLUDED - -#pragma once - -#include "react/detail/Defs.h" - -/*****************************************/ REACT_BEGIN /*****************************************/ - -/******************************************/ REACT_END /******************************************/ - -#endif // REACT_COMMON_OWNED_PTR_H_INCLUDED \ No newline at end of file diff --git a/include/react/detail/Defs.h b/include/react/detail/defs.h similarity index 100% rename from include/react/detail/Defs.h rename to include/react/detail/defs.h diff --git a/include/react/Event.h b/include/react/event.h similarity index 100% rename from include/react/Event.h rename to include/react/event.h diff --git a/include/react/Group.h b/include/react/group.h similarity index 100% rename from include/react/Group.h rename to include/react/group.h diff --git a/include/react/Observer.h b/include/react/observer.h similarity index 100% rename from include/react/Observer.h rename to include/react/observer.h From df1bf4b7c52d6017e74b959dc2d938b952c43f8a Mon Sep 17 00:00:00 2001 From: schlangster Date: Wed, 25 Oct 2017 01:32:45 +0200 Subject: [PATCH 56/75] Cleanup. Added event tests. --- include/react/detail/event_nodes.h | 30 +- include/react/detail/graph_interface.h | 1 - include/react/detail/node_base.h | 1 - include/react/event.h | 18 +- project/msvc/CppReactTest.vcxproj | 5 +- project/msvc/CppReactTest.vcxproj.filters | 15 +- src/detail/graph_impl.cpp | 5 +- tests/src/MoveTest.h | 134 -------- tests/src/ObserverTest.h | 242 ------------- tests/src/OperationsTest.cpp | 12 - .../src/{MoveTest.cpp => algorithm_tests.cpp} | 0 tests/src/event_tests.cpp | 323 +++++++++++++++++- .../{ObserverTest.cpp => observer_test.cpp} | 0 13 files changed, 354 insertions(+), 432 deletions(-) delete mode 100644 tests/src/MoveTest.h delete mode 100644 tests/src/ObserverTest.h delete mode 100644 tests/src/OperationsTest.cpp rename tests/src/{MoveTest.cpp => algorithm_tests.cpp} (100%) rename tests/src/{ObserverTest.cpp => observer_test.cpp} (100%) diff --git a/include/react/detail/event_nodes.h b/include/react/detail/event_nodes.h index dfec7020..d497acb3 100644 --- a/include/react/detail/event_nodes.h +++ b/include/react/detail/event_nodes.h @@ -121,15 +121,15 @@ class EventMergeNode : public EventNode ~EventMergeNode() { - apply([this] (const auto& ... deps) - { REACT_EXPAND_PACK(this->DetachFromMe(GetInternals(deps).GetNodeId())); }, depHolder_); + apply([this] (const auto& ... inputs) + { REACT_EXPAND_PACK(this->DetachFromMe(GetInternals(inputs).GetNodeId())); }, inputs_); this->UnregisterMe(); } virtual UpdateResult Update(TurnId turnId) noexcept override { - apply([this] (auto& ... deps) - { REACT_EXPAND_PACK(MergeFromDep(deps)); }, depHolder_); + apply([this] (auto& ... inputs) + { REACT_EXPAND_PACK(MergeFromInput(inputs)); }, inputs_); if (! this->Events().empty()) return UpdateResult::changed; @@ -141,7 +141,7 @@ class EventMergeNode : public EventNode template void MergeFromInput(Event& dep) { - EventInternals& depInternals = GetInternals(dep); + auto& depInternals = GetInternals(dep); this->Events().insert(this->Events().end(), depInternals.Events().begin(), depInternals.Events().end()); } @@ -340,22 +340,23 @@ class EventJoinNode : public EventNode> ~EventJoinNode() { - apply([this] (const auto& ... slots) { REACT_EXPAND_PACK(this->DetachFromMe(GetInternals(slots.source).GetNodeId())); }, slots_); + apply([this] (const auto& ... slots) + { REACT_EXPAND_PACK(this->DetachFromMe(GetInternals(slots.source).GetNodeId())); }, slots_); this->UnregisterMe(); } virtual UpdateResult Update(TurnId turnId) noexcept override { // Move events into buffers. - apply([this, turnId] (Slot& ... slots) { REACT_EXPAND_PACK(FetchBuffer(turnId, slots)); }, slots_); + apply([this, turnId] (Slot& ... slots) + { REACT_EXPAND_PACK(FetchBuffer(turnId, slots)); }, slots_); while (true) { bool isReady = true; // All slots ready? - apply( - [this, &isReady] (Slot& ... slots) + apply([this, &isReady] (Slot& ... slots) { // Todo: combine return values instead REACT_EXPAND_PACK(CheckSlot(slots, isReady)); @@ -366,8 +367,7 @@ class EventJoinNode : public EventNode> break; // Pop values from buffers and emit tuple. - apply( - [this] (Slot& ... slots) + apply([this] (Slot& ... slots) { this->Events().emplace_back(slots.buffer.front() ...); REACT_EXPAND_PACK(slots.buffer.pop_front()); @@ -376,14 +376,9 @@ class EventJoinNode : public EventNode> } if (! this->Events().empty()) - { - this->SetPendingSuccessorCount(successorCount); return UpdateResult::changed; - } else - { return UpdateResult::unchanged; - } } private: @@ -392,7 +387,7 @@ class EventJoinNode : public EventNode> { Slot(const Event& src) : source( src ) - { } + { } Event source; std::deque buffer; @@ -402,7 +397,6 @@ class EventJoinNode : public EventNode> static void FetchBuffer(TurnId turnId, Slot& slot) { slot.buffer.insert(slot.buffer.end(), GetInternals(slot.source).Events().begin(), GetInternals(slot.source).Events().end()); - GetInternals(slot.source).DecrementPendingSuccessorCount(); } template diff --git a/include/react/detail/graph_interface.h b/include/react/detail/graph_interface.h index 6fa51f89..8d0997b3 100644 --- a/include/react/detail/graph_interface.h +++ b/include/react/detail/graph_interface.h @@ -17,7 +17,6 @@ #include #include "react/api.h" -#include "react/common/types.h" #include "react/common/utility.h" /***************************************/ REACT_IMPL_BEGIN /**************************************/ diff --git a/include/react/detail/node_base.h b/include/react/detail/node_base.h index 6345d431..2f0c67fd 100644 --- a/include/react/detail/node_base.h +++ b/include/react/detail/node_base.h @@ -15,7 +15,6 @@ #include #include -#include "react/common/types.h" #include "react/common/utility.h" #include "react/detail/graph_interface.h" diff --git a/include/react/event.h b/include/react/event.h index 903d3dc6..5d67c8ce 100644 --- a/include/react/event.h +++ b/include/react/event.h @@ -291,12 +291,14 @@ class EventLink : public Event /// Merge /////////////////////////////////////////////////////////////////////////////////////////////////// template -auto Merge(const Group& group, const Event& dep1, const Event& ... deps) -> decltype(auto) +auto Merge(const Group& group, const Event& dep1, const Event& ... deps) -> Event { using REACT_IMPL::EventMergeNode; using REACT_IMPL::SameGroupOrLink; + using REACT_IMPL::CreateWrappedNode; - return Event::CreateWithNode>(group, SameGroupOrLink(group, dep1), SameGroupOrLink(group, deps) ...); + return CreateWrappedNode, EventMergeNode>( + group, SameGroupOrLink(group, dep1), SameGroupOrLink(group, deps) ...); } template @@ -342,8 +344,8 @@ auto Filter(F&& pred, const Event& dep, const State& ... states) -> Event template auto Transform(const Group& group, F&& op, const Event& dep) -> Event { - auto transformFunc = [capturedOp = std::forward(op)] (EventRange inRange, EventSink out) - { std::transform(inRange.begin(), inRange.end(), out, capturedOp); }; + auto transformFunc = [capturedOp = std::forward(op)] (const EventValueList& evts, EventValueSink out) + { std::transform(evts.begin(), evts.end(), out, capturedOp); }; return Event(group, std::move(transformFunc), dep); } @@ -355,9 +357,9 @@ auto Transform(F&& op, const Event& dep) -> Event template auto Transform(const Group& group, F&& op, const Event& dep, const State& ... states) -> Event { - auto transformFunc = [capturedOp = std::forward(pred)] (EventRange inRange, EventSink out, const Vs& ... values) + auto transformFunc = [capturedOp = std::forward(pred)] (const EventValueList& evts, EventValueSink out, const Us& ... values) { - for (const auto& v : inRange) + for (const auto& v : evts) *out++ = capturedPred(v, values ...); }; @@ -375,10 +377,12 @@ template auto Join(const Group& group, const Event& dep1, const Event& ... deps) -> Event> { using REACT_IMPL::EventJoinNode; + using REACT_IMPL::SameGroupOrLink; + using REACT_IMPL::CreateWrappedNode; static_assert(sizeof...(Us) > 0, "Join requires at least 2 inputs."); - return Event>::CreateWithNode>( + return CreateWrappedNode>, EventJoinNode>( group, SameGroupOrLink(group, dep1), SameGroupOrLink(group, deps) ...); } diff --git a/project/msvc/CppReactTest.vcxproj b/project/msvc/CppReactTest.vcxproj index 7516767f..eda051bb 100644 --- a/project/msvc/CppReactTest.vcxproj +++ b/project/msvc/CppReactTest.vcxproj @@ -164,9 +164,8 @@ - - - + + diff --git a/project/msvc/CppReactTest.vcxproj.filters b/project/msvc/CppReactTest.vcxproj.filters index 6004eeed..8ed9f84c 100644 --- a/project/msvc/CppReactTest.vcxproj.filters +++ b/project/msvc/CppReactTest.vcxproj.filters @@ -15,15 +15,6 @@ - - Source Files - - - Source Files - - - Source Files - Source Files @@ -39,5 +30,11 @@ Source Files + + Source Files + + + Source Files + \ No newline at end of file diff --git a/src/detail/graph_impl.cpp b/src/detail/graph_impl.cpp index c6ceb6be..fb44a252 100644 --- a/src/detail/graph_impl.cpp +++ b/src/detail/graph_impl.cpp @@ -16,11 +16,8 @@ #include #include -#include "react/detail/graph_impl.h" - -#include "react/common/types.h" -#include "react/common/expected.h" #include "react/detail/graph_interface.h" +#include "react/detail/graph_impl.h" /***************************************/ REACT_IMPL_BEGIN /**************************************/ diff --git a/tests/src/MoveTest.h b/tests/src/MoveTest.h deleted file mode 100644 index 0804423a..00000000 --- a/tests/src/MoveTest.h +++ /dev/null @@ -1,134 +0,0 @@ - -// Copyright Sebastian Jeckel 2017. -// 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) - -#pragma once - -#include "gtest/gtest.h" - -#include "react/Domain.h" -#include "react/Signal.h" - -/////////////////////////////////////////////////////////////////////////////////////////////////// -namespace { - -using namespace react; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// MoveTest fixture -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -class MoveTest : public testing::Test -{ -public: - template - class MyEngine : public TParams::template EngineT {}; - - REACTIVE_DOMAIN(MyDomain, TParams::mode, MyEngine) - - struct Stats - { - int copyCount = 0; - int moveCount = 0; - }; - - struct CopyCounter - { - int v = 0; - Stats* stats = nullptr; - - CopyCounter() = default; - - CopyCounter(int x, Stats* s) : - v( x ), - stats( s ) - {} - - CopyCounter(const CopyCounter& other) : - v( other.v ), - stats( other.stats ) - { - stats->copyCount++; - } - - CopyCounter(CopyCounter&& other) : - v( other.v ), - stats( other.stats ) - { - stats->moveCount++; - } - - CopyCounter& operator=(const CopyCounter& other) - { - v = other.v; - stats = other.stats; - stats->copyCount++; - return *this; - } - - CopyCounter& operator=(CopyCounter&& other) - { - v = other.v; - stats = other.stats; - stats->moveCount++; - return *this; - } - - CopyCounter operator+(const CopyCounter& r) const - { - return CopyCounter{ v + r.v, stats }; - } - - bool operator==(const CopyCounter& other) const - { - return v == other.v; - } - }; -}; - -TYPED_TEST_CASE_P(MoveTest); - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Copy1 -/////////////////////////////////////////////////////////////////////////////////////////////////// -TYPED_TEST_P(MoveTest, Copy1) -{ - using D = typename Copy1::MyDomain; - using CopyCounter = typename Copy1::CopyCounter; - using Stats = typename Copy1::Stats; - - Stats stats1; - - auto a = MakeVar(CopyCounter{1,&stats1}); - auto b = MakeVar(CopyCounter{10,&stats1}); - auto c = MakeVar(CopyCounter{100,&stats1}); - auto d = MakeVar(CopyCounter{1000,&stats1}); - - // 4x move to value_ - // 4x copy to newValue_ (can't be unitialized for references) - ASSERT_EQ(stats1.copyCount, 4); - ASSERT_EQ(stats1.moveCount, 4); - - auto x = a + b + c + d; - - ASSERT_EQ(stats1.copyCount, 4); - ASSERT_EQ(stats1.moveCount, 7); - ASSERT_EQ(x().v, 1111); - - a <<= CopyCounter{2,&stats1}; - - ASSERT_EQ(stats1.copyCount, 4); - ASSERT_EQ(stats1.moveCount, 10); - ASSERT_EQ(x().v, 1112); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -REGISTER_TYPED_TEST_CASE_P -( - MoveTest, - Copy1 -); - -} // ~namespace diff --git a/tests/src/ObserverTest.h b/tests/src/ObserverTest.h deleted file mode 100644 index 559c0686..00000000 --- a/tests/src/ObserverTest.h +++ /dev/null @@ -1,242 +0,0 @@ - -// Copyright Sebastian Jeckel 2017. -// 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) - -#pragma once - -#include "gtest/gtest.h" - -#include - -#include "react/Domain.h" -#include "react/Signal.h" -#include "react/Event.h" -#include "react/Observer.h" - -/////////////////////////////////////////////////////////////////////////////////////////////////// -namespace { - -using namespace react; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// ObserverTest fixture -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -class ObserverTest : public testing::Test -{ -public: - template - class MyEngine : public TParams::template EngineT {}; - - REACTIVE_DOMAIN(MyDomain, TParams::mode, MyEngine) -}; - -TYPED_TEST_CASE_P(ObserverTest); - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Detach test -/////////////////////////////////////////////////////////////////////////////////////////////////// -TYPED_TEST_P(ObserverTest, Detach) -{ - using D = typename Detach::MyDomain; - - auto a1 = MakeVar(1); - auto a2 = MakeVar(1); - - auto result = a1 + a2; - - int observeCount1 = 0; - int observeCount2 = 0; - int observeCount3 = 0; - - int phase; - - auto obs1 = Observe(result, [&] (int v) - { - observeCount1++; - - if (phase == 0) - ASSERT_EQ(v,3); - else if (phase == 1) - ASSERT_EQ(v,4); - else - ASSERT_TRUE(false); - }); - - auto obs2 = Observe(result, [&] (int v) - { - observeCount2++; - - if (phase == 0) - ASSERT_EQ(v,3); - else if (phase == 1) - ASSERT_EQ(v,4); - else - ASSERT_TRUE(false); - }); - - auto obs3 = Observe(result, [&] (int v) - { - observeCount3++; - - if (phase == 0) - ASSERT_EQ(v,3); - else if (phase == 1) - ASSERT_EQ(v,4); - else - ASSERT_TRUE(false); - }); - - phase = 0; - a1 <<= 2; - ASSERT_EQ(observeCount1,1); - ASSERT_EQ(observeCount2,1); - ASSERT_EQ(observeCount3,1); - - phase = 1; - obs1.Detach(); - a1 <<= 3; - ASSERT_EQ(observeCount1,1); - ASSERT_EQ(observeCount2,2); - ASSERT_EQ(observeCount3,2); - - phase = 2; - obs2.Detach(); - obs3.Detach(); - a1 <<= 4; - ASSERT_EQ(observeCount1,1); - ASSERT_EQ(observeCount2,2); - ASSERT_EQ(observeCount3,2); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// ScopedObserver test -/////////////////////////////////////////////////////////////////////////////////////////////////// -TYPED_TEST_P(ObserverTest, ScopedObserverTest) -{ - using D = typename ScopedObserverTest::MyDomain; - - std::vector results; - - auto in = MakeVar(1); - - { - ScopedObserver obs = Observe(in, [&] (int v) { - results.push_back(v); - }); - - in <<=2; - } - - in <<=3; - - ASSERT_EQ(results.size(),1); - ASSERT_EQ(results[0], 2); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Synced Observe test -/////////////////////////////////////////////////////////////////////////////////////////////////// -TYPED_TEST_P(ObserverTest, SyncedObserveTest) -{ - using D = typename SyncedObserveTest::MyDomain; - - auto in1 = MakeVar(1); - auto in2 = MakeVar(1); - - auto sum = in1 + in2; - auto prod = in1 * in2; - auto diff = in1 - in2; - - auto src1 = MakeEventSource(); - auto src2 = MakeEventSource(); - - Observe(src1, With(sum,prod,diff), [] (Token, int sum, int prod, int diff) { - ASSERT_EQ(sum, 33); - ASSERT_EQ(prod, 242); - ASSERT_EQ(diff, 11); - }); - - Observe(src2, With(sum,prod,diff), [] (int e, int sum, int prod, int diff) { - ASSERT_EQ(e, 42); - ASSERT_EQ(sum, 33); - ASSERT_EQ(prod, 242); - ASSERT_EQ(diff, 11); - }); - - in1 <<= 22; - in2 <<= 11; - - src1.Emit(); - src2.Emit(42); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// DetachThisObserver1 test -/////////////////////////////////////////////////////////////////////////////////////////////////// -TYPED_TEST_P(ObserverTest, DetachThisObserver1) -{ - using D = typename DetachThisObserver1::MyDomain; - - auto src = MakeEventSource(); - - int count = 0; - - Observe(src, [&] (Token) -> ObserverAction { - ++count; - return ObserverAction::stop_and_detach; - }); - - src.Emit(); - src.Emit(); - - printf("Count %d\n", count); - ASSERT_EQ(count, 1); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// DetachThisObserver2 test -/////////////////////////////////////////////////////////////////////////////////////////////////// -TYPED_TEST_P(ObserverTest, DetachThisObserver2) -{ - using D = typename DetachThisObserver2::MyDomain; - - auto in1 = MakeVar(1); - auto in2 = MakeVar(1); - - auto sum = in1 + in2; - auto prod = in1 * in2; - auto diff = in1 - in2; - - auto src = MakeEventSource(); - - int count = 0; - - Observe(src, With(sum,prod,diff), [&] (Token, int sum, int prod, int diff) -> ObserverAction { - ++count; - return ObserverAction::stop_and_detach; - }); - - in1 <<= 22; - in2 <<= 11; - - src.Emit(); - src.Emit(); - - ASSERT_EQ(count, 1); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -REGISTER_TYPED_TEST_CASE_P -( - ObserverTest, - Detach, - ScopedObserverTest, - SyncedObserveTest, - DetachThisObserver1, - DetachThisObserver2 -); - -} // ~namespace diff --git a/tests/src/OperationsTest.cpp b/tests/src/OperationsTest.cpp deleted file mode 100644 index 6054092a..00000000 --- a/tests/src/OperationsTest.cpp +++ /dev/null @@ -1,12 +0,0 @@ - -// Copyright Sebastian Jeckel 2017. -// 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) - - -/////////////////////////////////////////////////////////////////////////////////////////////////// -namespace { - - -} // ~namespace \ No newline at end of file diff --git a/tests/src/MoveTest.cpp b/tests/src/algorithm_tests.cpp similarity index 100% rename from tests/src/MoveTest.cpp rename to tests/src/algorithm_tests.cpp diff --git a/tests/src/event_tests.cpp b/tests/src/event_tests.cpp index 31565b87..98d27bfc 100644 --- a/tests/src/event_tests.cpp +++ b/tests/src/event_tests.cpp @@ -9,8 +9,12 @@ #include "react/event.h" #include "react/observer.h" -#include +#include #include +#include +#include +#include +#include using namespace react; @@ -216,4 +220,321 @@ TEST(EventTest, Links) EXPECT_EQ(3, output); EXPECT_EQ(3, turns); +} + +TEST(EventTest, EventSources) +{ + Group g; + + EventSource es1( g ); + EventSource es2( g ); + + std::queue results1; + std::queue results2; + + Observer obs1([&] (const auto& events) + { + for (int e : events) + results1.push(e); + }, es1); + + Observer obs2([&] (const auto& events) + { + for (int e : events) + results2.push(e); + }, es2); + + es1.Emit(10); + es1.Emit(20); + es1.Emit(30); + + es2.Emit(40); + es2.Emit(50); + es2.Emit(60); + + // First batch. + EXPECT_FALSE(results1.empty()); + EXPECT_EQ(results1.front(), 10); + results1.pop(); + + EXPECT_FALSE(results1.empty()); + EXPECT_EQ(results1.front(), 20); + results1.pop(); + + EXPECT_FALSE(results1.empty()); + EXPECT_EQ(results1.front(),30); + results1.pop(); + + EXPECT_TRUE(results1.empty()); + + // Second batch. + EXPECT_FALSE(results2.empty()); + EXPECT_EQ(results2.front(),40); + results2.pop(); + + EXPECT_FALSE(results2.empty()); + EXPECT_EQ(results2.front(),50); + results2.pop(); + + EXPECT_FALSE(results2.empty()); + EXPECT_EQ(results2.front(),60); + results2.pop(); + + EXPECT_TRUE(results2.empty()); +} + +TEST(EventTest, Merge1) +{ + Group g; + + EventSource a1( g ); + EventSource a2( g ); + EventSource a3( g ); + + Event merged = Merge(g, a1, a2, a3); + + std::vector results; + + Observer obs1([&] (const auto& events) + { + for (int e : events) + results.push_back(e); + }, merged); + + g.DoTransaction([&] + { + a1.Emit(10); + a2.Emit(20); + a3.Emit(30); + }); + + EXPECT_EQ(results.size(), 3); + + EXPECT_TRUE(std::find(results.begin(), results.end(), 10) != results.end()); + EXPECT_TRUE(std::find(results.begin(), results.end(), 20) != results.end()); + EXPECT_TRUE(std::find(results.begin(), results.end(), 30) != results.end()); +} + +TEST(EventTest, Merge2) +{ + Group g; + + EventSource a1( g ); + EventSource a2( g ); + EventSource a3( g ); + + Event merged = Merge(a1, a2, a3); + + std::vector results; + + Observer obs1([&] (const auto& events) + { + for (const auto& e : events) + results.push_back(e); + }, merged); + + std::string s1("one"); + std::string s2("two"); + std::string s3("three"); + + g.DoTransaction([&] + { + a1.Emit(s1); + a2.Emit(s2); + a3.Emit(s3); + }); + + EXPECT_EQ(results.size(), 3); + + EXPECT_TRUE(std::find(results.begin(), results.end(), "one") != results.end()); + EXPECT_TRUE(std::find(results.begin(), results.end(), "two") != results.end()); + EXPECT_TRUE(std::find(results.begin(), results.end(), "three") != results.end()); +} + +TEST(EventTest, Merge3) +{ + Group g; + + EventSource a1( g ); + EventSource a2( g ); + + Event f1 = Filter([] (int v) { return true; }, a1); + Event f2 = Filter([] (int v) { return true; }, a2); + + Event merged = Merge(f1, f2); + + std::queue results; + + Observer obs1([&] (const auto& events) + { + for (int e : events) + results.push(e); + }, merged); + + a1.Emit(10); + a2.Emit(20); + a1.Emit(30); + + EXPECT_FALSE(results.empty()); + EXPECT_EQ(results.front(), 10); + results.pop(); + + EXPECT_FALSE(results.empty()); + EXPECT_EQ(results.front(), 20); + results.pop(); + + EXPECT_FALSE(results.empty()); + EXPECT_EQ(results.front(), 30); + results.pop(); + + EXPECT_TRUE(results.empty()); +} + +TEST(EventTest, Filter) +{ + Group g; + + EventSource in( g ); + + std::queue results; + + Event filtered = Filter(g, [] (const std::string& s) + { + return s == "Hello World"; + }, in); + + Observer obs1([&] (const auto& events) + { + for (const auto& e : events) + results.push(e); + }, filtered); + + in.Emit(std::string("Hello Worlt")); + in.Emit(std::string("Hello World")); + in.Emit(std::string("Hello Vorld")); + + EXPECT_FALSE(results.empty()); + EXPECT_EQ(results.front(), "Hello World"); + results.pop(); + + EXPECT_TRUE(results.empty()); +} + +TEST(EventTest, Transform) +{ + Group g; + + EventSource in1( g ); + EventSource in2( g ); + + std::vector results; + + Event merged = Merge(in1, in2); + + Event transformed = Transform([] (std::string s) -> std::string + { + std::transform(s.begin(), s.end(), s.begin(), ::toupper); + return s; + }, merged); + + Observer obs1([&] (const auto& events) + { + for (const auto& e : events) + results.push_back(e); + }, transformed); + + in1.Emit(std::string("Hello Worlt")); + in1.Emit(std::string("Hello World")); + in2.Emit(std::string("Hello Vorld")); + + EXPECT_EQ(results.size(), 3); + EXPECT_TRUE(std::find(results.begin(), results.end(), "HELLO WORLT") != results.end()); + EXPECT_TRUE(std::find(results.begin(), results.end(), "HELLO WORLD") != results.end()); + EXPECT_TRUE(std::find(results.begin(), results.end(), "HELLO VORLD") != results.end()); +} + +TEST(EventTest, Chain) +{ + Group g; + + std::vector results; + + EventSource in1( g ); + EventSource in2( g ); + + auto merged = Merge(in1, in2); + int turns = 0; + + Event processed([&] (const auto& events, auto out) + { + for (const auto& e : events) + { + *out = 0.1f * e; + *out = 1.5f * e; + } + + ++turns; + }, merged); + + Observer obs1([&] (const auto& events) + { + for (float e : events) + results.push_back(e); + }, processed); + + g.DoTransaction([&] { + in1.Emit(10); + in1.Emit(20); + }); + + in2 << 30; + + EXPECT_EQ(results.size(), 6); + EXPECT_EQ(turns, 2); + + EXPECT_EQ(results[0], 1.0f); + EXPECT_EQ(results[1], 15.0f); + EXPECT_EQ(results[2], 2.0f); + EXPECT_EQ(results[3], 30.0f); + EXPECT_EQ(results[4], 3.0f); + EXPECT_EQ(results[5], 45.0f); +} + +TEST(EventTest, Join) +{ + Group g; + + EventSource in1( g ); + EventSource in2( g ); + EventSource in3( g ); + + Event> joined = Join(in1, in2, in3); + + std::vector> results; + + Observer obs1([&] (const auto& events) + { + for (const auto& e : events) + results.push_back(e); + }, joined); + + in1.Emit(10); + EXPECT_EQ(results.size(), 0); + + in2.Emit(10); + EXPECT_EQ(results.size(), 0); + + in2.Emit(20); + EXPECT_EQ(results.size(), 0); + + in3.Emit(10); + EXPECT_EQ(results.size(), 1); + EXPECT_EQ(results[0], std::make_tuple(10, 10, 10)); + + in3.Emit(20); + EXPECT_EQ(results.size(), 1); + + in1.Emit(20); + EXPECT_EQ(results.size(), 2); + EXPECT_EQ(results[1], std::make_tuple(20, 20, 20)); } \ No newline at end of file diff --git a/tests/src/ObserverTest.cpp b/tests/src/observer_test.cpp similarity index 100% rename from tests/src/ObserverTest.cpp rename to tests/src/observer_test.cpp From 55fbe9b961784f7820cb63e62e2b1c66842e84a5 Mon Sep 17 00:00:00 2001 From: schlangster Date: Thu, 26 Oct 2017 00:44:34 +0200 Subject: [PATCH 57/75] Removed obsolete files. Added more tests. --- include/react/algorithm.h | 10 +- include/react/api.h | 2 + include/react/detail/algorithm_nodes.h | 62 +- include/react/detail/event_nodes.h | 16 +- include/react/detail/state_nodes.h | 2 +- include/react/event.h | 43 +- project/msvc/CppReactTest.vcxproj | 1 - project/msvc/CppReactTest.vcxproj.filters | 3 - tests/src/EventStreamTest.h | 335 -------- tests/src/EventStreamTestQ.cpp | 29 - tests/src/ObserverTestQ.cpp | 29 - tests/src/OperationsTest.h | 971 ---------------------- tests/src/OperationsTestQ.cpp | 29 - tests/src/ParallelizationTest.cpp | 12 - tests/src/ParallelizationTest.h | 63 -- tests/src/SignalTest.h | 664 --------------- tests/src/SignalTestQ.cpp | 29 - tests/src/TestUtil.h | 25 - tests/src/TransactionTest.h | 571 ------------- tests/src/algorithm_tests.cpp | 708 +++++++++++++++- tests/src/event_tests.cpp | 149 +++- tests/src/state_tests.cpp | 167 +++- tests/src/transaction_tests.cpp | 7 +- 23 files changed, 1065 insertions(+), 2862 deletions(-) delete mode 100644 tests/src/EventStreamTest.h delete mode 100644 tests/src/EventStreamTestQ.cpp delete mode 100644 tests/src/ObserverTestQ.cpp delete mode 100644 tests/src/OperationsTest.h delete mode 100644 tests/src/OperationsTestQ.cpp delete mode 100644 tests/src/ParallelizationTest.cpp delete mode 100644 tests/src/ParallelizationTest.h delete mode 100644 tests/src/SignalTest.h delete mode 100644 tests/src/SignalTestQ.cpp delete mode 100644 tests/src/TestUtil.h delete mode 100644 tests/src/TransactionTest.h diff --git a/include/react/algorithm.h b/include/react/algorithm.h index 9c1b2023..075f3d3c 100644 --- a/include/react/algorithm.h +++ b/include/react/algorithm.h @@ -15,12 +15,12 @@ #include #include -#include "react/API.h" -#include "react/detail/algorithm_nodes.h" - +#include "react/api.h" #include "react/state.h" #include "react/event.h" +#include "react/detail/algorithm_nodes.h" + /*****************************************/ REACT_BEGIN /*****************************************/ /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -66,7 +66,6 @@ template auto Iterate(const Group& group, T&& initialValue, F&& func, const Event& evnt) -> State { using REACT_IMPL::IterateNode; - using REACT_IMPL::IsCallableWith; using REACT_IMPL::SameGroupOrLink; using REACT_IMPL::CreateWrappedNode; @@ -80,7 +79,6 @@ template auto IterateByRef(const Group& group, T&& initialValue, F&& func, const Event& evnt) -> State { using REACT_IMPL::IterateByRefNode; - using REACT_IMPL::IsCallableWith; using REACT_IMPL::SameGroupOrLink; using REACT_IMPL::CreateWrappedNode; @@ -105,7 +103,6 @@ template auto Iterate(const Group& group, T&& initialValue, F&& func, const Event& evnt, const State& ... states) -> State { using REACT_IMPL::SyncedIterateNode; - using REACT_IMPL::IsCallableWith; using REACT_IMPL::SameGroupOrLink; using REACT_IMPL::CreateWrappedNode; @@ -119,7 +116,6 @@ template auto IterateByRef(const Group& group, T&& initialValue, F&& func, const Event& evnt, const State& ... states) -> State { using REACT_IMPL::SyncedIterateByRefNode; - using REACT_IMPL::IsCallableWith; using REACT_IMPL::SameGroupOrLink; using REACT_IMPL::CreateWrappedNode; diff --git a/include/react/api.h b/include/react/api.h index 89ace35c..d8d15204 100644 --- a/include/react/api.h +++ b/include/react/api.h @@ -33,6 +33,8 @@ enum class TransactionFlags REACT_DEFINE_BITMASK_OPERATORS(TransactionFlags) +enum class Token { value }; + /////////////////////////////////////////////////////////////////////////////////////////////////// /// API types /////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/include/react/detail/algorithm_nodes.h b/include/react/detail/algorithm_nodes.h index b0a7d9da..968080d5 100644 --- a/include/react/detail/algorithm_nodes.h +++ b/include/react/detail/algorithm_nodes.h @@ -44,7 +44,7 @@ class IterateNode : public StateNode virtual UpdateResult Update(TurnId turnId) noexcept override { - S newValue = func_(EventRange( GetInternals(evnt_).Events() ), this->Value()); + S newValue = func_(GetInternals(evnt_).Events(), this->Value()); if (! (newValue == this->Value())) { @@ -81,15 +81,15 @@ class IterateByRefNode : public StateNode ~IterateByRefNode() { - this->DetachFromMe(GetInternals(evnt).GetNodeId()); + this->DetachFromMe(GetInternals(evnt_).GetNodeId()); this->UnregisterMe(); } virtual UpdateResult Update(TurnId turnId) noexcept override { - func_(EventRange( GetInternals(evnt_).Events() ), this->Value()); + func_(GetInternals(evnt_).Events(), this->Value()); - // Always assume change + // Always assume a change return UpdateResult::changed; } @@ -119,7 +119,8 @@ class SyncedIterateNode : public StateNode ~SyncedIterateNode() { - apply([this] (const auto& ... syncs) { REACT_EXPAND_PACK(this->DetachFromMe(GetInternals(syncs).GetNodeId())); }, syncHolder_); + apply([this] (const auto& ... syncs) + { REACT_EXPAND_PACK(this->DetachFromMe(GetInternals(syncs).GetNodeId())); }, syncHolder_); this->DetachFromMe(GetInternals(evnt_).GetNodeId()); this->UnregisterMe(); } @@ -130,12 +131,10 @@ class SyncedIterateNode : public StateNode if (GetInternals(evnt_).Events().empty()) return UpdateResult::unchanged; - S newValue = apply( - [this] (const auto& ... syncs) + S newValue = apply([this] (const auto& ... syncs) { - return func_(EventRange( GetInternals(evnt_).Events() ), this->Value(), GetInternals(syncs).Value() ...); - }, - syncHolder_); + return func_(GetInternals(evnt_).Events(), this->Value(), GetInternals(syncs).Value() ...); + }, syncHolder_); if (! (newValue == this->Value())) { @@ -190,7 +189,7 @@ class SyncedIterateByRefNode : public StateNode apply( [this] (const auto& ... args) { - func_(EventRange( GetInternals(evnt_).Events() ), this->Value(), GetInternals(args).Value() ...); + func_(GetInternals(evnt_).Events(), this->Value(), GetInternals(args).Value() ...); }, syncHolder_); @@ -199,7 +198,7 @@ class SyncedIterateByRefNode : public StateNode private: F func_; - Event events_; + Event evnt_; std::tuple ...> syncHolder_; }; @@ -305,75 +304,70 @@ class SnapshotNode : public StateNode /// MonitorNode /////////////////////////////////////////////////////////////////////////////////////////////////// template -class MonitorNode : public EventStreamNode +class MonitorNode : public EventNode { public: - MonitorNode(const Group& group, const State& target) : - MonitorNode::EventStreamNode( group ), - target_( target ) + MonitorNode(const Group& group, const State& input) : + MonitorNode::EventNode( group ), + input_( input ) { this->RegisterMe(); - this->AttachToMe(GetInternals(target).GetNodeId()); + this->AttachToMe(GetInternals(input_).GetNodeId()); } ~MonitorNode() { - this->DetachFromMe(GetInternals(target_).GetNodeId()); + this->DetachFromMe(GetInternals(input_).GetNodeId()); this->UnregisterMe(); } virtual UpdateResult Update(TurnId turnId) noexcept override { - this->Events().push_back(GetInternals(target_).Value()); - + this->Events().push_back(GetInternals(input_).Value()); return UpdateResult::changed; } private: - State target_; + State input_; }; /////////////////////////////////////////////////////////////////////////////////////////////////// /// PulseNode /////////////////////////////////////////////////////////////////////////////////////////////////// template -class PulseNode : public EventStreamNode +class PulseNode : public EventNode { public: - PulseNode(const Group& group, const State& target, const Event& trigger) : - PulseNode::EventStreamNode( group ), - target_( target ), + PulseNode(const Group& group, const State& input, const Event& trigger) : + PulseNode::EventNode( group ), + input_( input ), trigger_( trigger ) { this->RegisterMe(); - this->AttachToMe(GetInternals(target).GetNodeId()); + this->AttachToMe(GetInternals(input).GetNodeId()); this->AttachToMe(GetInternals(trigger).GetNodeId()); } ~PulseNode() { this->DetachFromMe(GetInternals(trigger_).GetNodeId()); - this->DetachFromMe(GetInternals(target_).GetNodeId()); + this->DetachFromMe(GetInternals(input_).GetNodeId()); this->UnregisterMe(); } virtual UpdateResult Update(TurnId turnId) noexcept override { - for (size_t i = 0; i < GetInternals(trigger_).Events().size(); i++) - this->Events().push_back(GetInternals(target_).Value()); + for (size_t i = 0; i < GetInternals(trigger_).Events().size(); ++i) + this->Events().push_back(GetInternals(input_).Value()); if (! this->Events().empty()) - { return UpdateResult::changed; - } else - { return UpdateResult::unchanged; - } } private: - State target_; + State input_; Event trigger_; }; diff --git a/include/react/detail/event_nodes.h b/include/react/detail/event_nodes.h index d497acb3..7c988b23 100644 --- a/include/react/detail/event_nodes.h +++ b/include/react/detail/event_nodes.h @@ -285,27 +285,27 @@ class SyncedEventProcessingNode : public EventNode syncHolder_( syncs ... ) { this->RegisterMe(); - this->AttachToMe(dep->GetNodeId()); - REACT_EXPAND_PACK(this->AttachToMe(syncs->GetNodeId())); + this->AttachToMe(GetInternals(dep).GetNodeId()); + REACT_EXPAND_PACK(this->AttachToMe(GetInternals(syncs).GetNodeId())); } ~SyncedEventProcessingNode() { - apply([this] (const auto& ... syncs) { REACT_EXPAND_PACK(this->DetachFromMe(syncs->GetNodeId())); }, syncHolder_); - this->DetachFromMe(dep_->GetNodeId()); + apply([this] (const auto& ... syncs) + { REACT_EXPAND_PACK(this->DetachFromMe(GetInternals(syncs).GetNodeId())); }, syncHolder_); + this->DetachFromMe(GetInternals(dep_).GetNodeId()); this->UnregisterMe(); } virtual UpdateResult Update(TurnId turnId) noexcept override { // Updates might be triggered even if only sync nodes changed. Ignore those. - if (dep_->Events().empty()) + if (GetInternals(dep_).Events().empty()) return UpdateResult::unchanged; - apply( - [this] (const auto& ... syncs) + apply([this] (const auto& ... syncs) { - func_(EventRange( this->dep_->Events() ), std::back_inserter(this->Events()), syncs->Value() ...); + func_(GetInternals(dep_).Events(), std::back_inserter(this->Events()), GetInternals(syncs).Value() ...); }, syncHolder_); diff --git a/include/react/detail/state_nodes.h b/include/react/detail/state_nodes.h index 655ab542..c3b717b2 100644 --- a/include/react/detail/state_nodes.h +++ b/include/react/detail/state_nodes.h @@ -261,7 +261,7 @@ class StateSlotNode : public StateNode { return UpdateResult::changed; } }; - State input_; + State input_; NodeId inputNodeId_; VirtualInputNode slotInput_; diff --git a/include/react/event.h b/include/react/event.h index 5d67c8ce..ecde17b2 100644 --- a/include/react/event.h +++ b/include/react/event.h @@ -10,17 +10,17 @@ #pragma once #include "react/detail/defs.h" -#include "react/api.h" -#include "react/group.h" -#include "react/common/ptrcache.h" #include #include #include -#include "react/detail/event_nodes.h" +#include "react/api.h" +#include "react/group.h" +#include "react/detail/event_nodes.h" +#include "react/common/ptrcache.h" /*****************************************/ REACT_BEGIN /*****************************************/ @@ -136,12 +136,12 @@ class EventSource : public Event void Emit(E&& value) { EmitValue(std::move(value)); } - template >::type> + template >> void Emit() { EmitValue(Token::value); } EventSource& operator<<(const E& value) - { EmitValue(e); return *this; } + { EmitValue(value); return *this; } EventSource& operator<<(E&& value) { EmitValue(std::move(value)); return *this; } @@ -311,8 +311,8 @@ auto Merge(const Event& dep1, const Event& ... deps) -> decltype(auto) template auto Filter(const Group& group, F&& pred, const Event& dep) -> Event { - auto filterFunc = [capturedPred = std::forward(pred)] (const EventValueList& evts, EventValueSink out) - { std::copy_if(evts.begin(), evts.end(), out, capturedPred); }; + auto filterFunc = [capturedPred = std::forward(pred)] (const EventValueList& events, EventValueSink out) + { std::copy_if(events.begin(), events.end(), out, capturedPred); }; return Event(group, std::move(filterFunc), dep); } @@ -324,19 +324,19 @@ auto Filter(F&& pred, const Event& dep) -> Event template auto Filter(const Group& group, F&& pred, const Event& dep, const State& ... states) -> Event { - auto filterFunc = [capturedPred = std::forward(pred)] (const EventValueList& evts, EventValueSink out, const Us& ... values) + auto filterFunc = [capturedPred = std::forward(pred)] (const EventValueList& evts, EventValueSink out, const Ts& ... values) { for (const auto& v : evts) if (capturedPred(v, values ...)) *out++ = v; }; - return Event(group, std::move(filterFunc), dep, State ...); + return Event(group, std::move(filterFunc), dep, states ...); } template auto Filter(F&& pred, const Event& dep, const State& ... states) -> Event - { return Filter(dep.GetGroup(), std::forward(pred), dep); } + { return Filter(dep.GetGroup(), std::forward(pred), dep, states ...); } /////////////////////////////////////////////////////////////////////////////////////////////////// /// Transform @@ -357,10 +357,10 @@ auto Transform(F&& op, const Event& dep) -> Event template auto Transform(const Group& group, F&& op, const Event& dep, const State& ... states) -> Event { - auto transformFunc = [capturedOp = std::forward(pred)] (const EventValueList& evts, EventValueSink out, const Us& ... values) + auto transformFunc = [capturedOp = std::forward(op)] (const EventValueList& evts, EventValueSink out, const Us& ... values) { for (const auto& v : evts) - *out++ = capturedPred(v, values ...); + *out++ = capturedOp(v, values ...); }; return Event(group, std::move(transformFunc), dep, states ...); @@ -390,23 +390,6 @@ template auto Join(const Event& dep1, const Event& ... deps) -> Event> { return Join(dep1.GetGroup(), dep1, deps ...); } -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Token -/////////////////////////////////////////////////////////////////////////////////////////////////// -enum class Token { value }; - -/*struct Tokenizer -{ - template - Token operator()(const T&) const { return Token::value; } -}; - -template -auto Tokenize(T&& source) -> decltype(auto) -{ - return Transform(source, Tokenizer{ }); -}*/ - /******************************************/ REACT_END /******************************************/ /***************************************/ REACT_IMPL_BEGIN /**************************************/ diff --git a/project/msvc/CppReactTest.vcxproj b/project/msvc/CppReactTest.vcxproj index eda051bb..9cecab98 100644 --- a/project/msvc/CppReactTest.vcxproj +++ b/project/msvc/CppReactTest.vcxproj @@ -166,7 +166,6 @@ - diff --git a/project/msvc/CppReactTest.vcxproj.filters b/project/msvc/CppReactTest.vcxproj.filters index 8ed9f84c..d60eac41 100644 --- a/project/msvc/CppReactTest.vcxproj.filters +++ b/project/msvc/CppReactTest.vcxproj.filters @@ -15,9 +15,6 @@ - - Source Files - Source Files diff --git a/tests/src/EventStreamTest.h b/tests/src/EventStreamTest.h deleted file mode 100644 index db12a8ea..00000000 --- a/tests/src/EventStreamTest.h +++ /dev/null @@ -1,335 +0,0 @@ - -// Copyright Sebastian Jeckel 2017. -// 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) - -#pragma once - -#include -#include - -#include "gtest/gtest.h" - -#include "react/Domain.h" -#include "react/Event.h" - -/////////////////////////////////////////////////////////////////////////////////////////////////// -namespace { - -using namespace react; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// EventStreamTest fixture -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -class EventStreamTest : public testing::Test -{ -public: - template - class MyEngine : public TParams::template EngineT {}; - - REACTIVE_DOMAIN(MyDomain, TParams::mode, MyEngine) -}; - -TYPED_TEST_CASE_P(EventStreamTest); - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// EventSources test -/////////////////////////////////////////////////////////////////////////////////////////////////// -TYPED_TEST_P(EventStreamTest, EventSources) -{ - using D = typename EventSources::MyDomain; - - auto es1 = MakeEventSource(); - auto es2 = MakeEventSource(); - - std::queue results1; - std::queue results2; - - Observe(es1, [&] (int v) - { - results1.push(v); - }); - - Observe(es2, [&] (int v) - { - results2.push(v); - }); - - es1 << 10 << 20 << 30; - es2 << 40 << 50 << 60; - - // 1 - ASSERT_FALSE(results1.empty()); - ASSERT_EQ(results1.front(),10); - results1.pop(); - - ASSERT_FALSE(results1.empty()); - ASSERT_EQ(results1.front(),20); - results1.pop(); - - ASSERT_FALSE(results1.empty()); - ASSERT_EQ(results1.front(),30); - results1.pop(); - - ASSERT_TRUE(results1.empty()); - - // 2 - ASSERT_FALSE(results2.empty()); - ASSERT_EQ(results2.front(),40); - results2.pop(); - - ASSERT_FALSE(results2.empty()); - ASSERT_EQ(results2.front(),50); - results2.pop(); - - ASSERT_FALSE(results2.empty()); - ASSERT_EQ(results2.front(),60); - results2.pop(); - - ASSERT_TRUE(results2.empty()); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// EventMerge1 test -/////////////////////////////////////////////////////////////////////////////////////////////////// -TYPED_TEST_P(EventStreamTest, EventMerge1) -{ - using D = typename EventMerge1::MyDomain; - - auto a1 = MakeEventSource(); - auto a2 = MakeEventSource(); - auto a3 = MakeEventSource(); - - auto merged = Merge(a1, a2, a3); - - std::vector results; - - Observe(merged, [&] (int v) - { - results.push_back(v); - }); - - DoTransaction([&] { - a1 << 10; - a2 << 20; - a3 << 30; - }); - - ASSERT_EQ(results.size(), 3); - ASSERT_TRUE(std::find(results.begin(), results.end(), 10) != results.end()); - ASSERT_TRUE(std::find(results.begin(), results.end(), 20) != results.end()); - ASSERT_TRUE(std::find(results.begin(), results.end(), 30) != results.end()); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// EventMerge2 test -/////////////////////////////////////////////////////////////////////////////////////////////////// -TYPED_TEST_P(EventStreamTest, EventMerge2) -{ - using D = typename EventMerge2::MyDomain; - - auto a1 = MakeEventSource(); - auto a2 = MakeEventSource(); - auto a3 = MakeEventSource(); - - auto merged = Merge(a1, a2, a3); - - std::vector results; - - Observe(merged, [&] (std::string s) - { - results.push_back(s); - }); - - std::string s1("one"); - std::string s2("two"); - std::string s3("three"); - - DoTransaction([&] { - a1 << s1; - a2 << s2; - a3 << s3; - }); - - ASSERT_EQ(results.size(), 3); - ASSERT_TRUE(std::find(results.begin(), results.end(), "one") != results.end()); - ASSERT_TRUE(std::find(results.begin(), results.end(), "two") != results.end()); - ASSERT_TRUE(std::find(results.begin(), results.end(), "three") != results.end()); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// EventMerge3 test -/////////////////////////////////////////////////////////////////////////////////////////////////// -TYPED_TEST_P(EventStreamTest, EventMerge3) -{ - using D = typename EventMerge3::MyDomain; - - auto a1 = MakeEventSource(); - auto a2 = MakeEventSource(); - - auto f1 = Filter(a1, [] (int v) { return true; }); - auto f2 = Filter(a2, [] (int v) { return true; }); - - auto merged = Merge(f1, f2); - - std::queue results; - - Observe(merged, [&] (int s) - { - results.push(s); - }); - - a1 << 10; - a2 << 20; - a1 << 30; - - ASSERT_FALSE(results.empty()); - ASSERT_EQ(results.front(),10); - results.pop(); - - ASSERT_FALSE(results.empty()); - ASSERT_EQ(results.front(),20); - results.pop(); - - ASSERT_FALSE(results.empty()); - ASSERT_EQ(results.front(),30); - results.pop(); - - ASSERT_TRUE(results.empty()); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// EventFilter test -/////////////////////////////////////////////////////////////////////////////////////////////////// -TYPED_TEST_P(EventStreamTest, EventFilter) -{ - using D = typename EventFilter::MyDomain; - - using std::string; - - std::queue results; - - auto in = MakeEventSource(); - - auto filtered = Filter(in, [] (const string& s) - { - return s == "Hello World"; - }); - - - Observe(filtered, [&] (const string& s) - { - results.push(s); - }); - - in << string("Hello Worlt") << string("Hello World") << string("Hello Vorld"); - - ASSERT_FALSE(results.empty()); - ASSERT_EQ(results.front(), "Hello World"); - results.pop(); - - ASSERT_TRUE(results.empty()); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// EventTransform test -/////////////////////////////////////////////////////////////////////////////////////////////////// -TYPED_TEST_P(EventStreamTest, EventTransform) -{ - using D = typename EventTransform::MyDomain; - - using std::string; - - std::vector results; - - auto in1 = MakeEventSource(); - auto in2 = MakeEventSource(); - - auto merged = Merge(in1, in2); - - auto transformed = Transform(merged, [] (string s) -> string - { - std::transform(s.begin(), s.end(), s.begin(), ::toupper); - return s; - }); - - Observe(transformed, [&] (const string& s) - { - results.push_back(s); - }); - - in1 << string("Hello Worlt") << string("Hello World"); - in2 << string("Hello Vorld"); - - ASSERT_EQ(results.size(), 3); - ASSERT_TRUE(std::find(results.begin(), results.end(), "HELLO WORLT") != results.end()); - ASSERT_TRUE(std::find(results.begin(), results.end(), "HELLO WORLD") != results.end()); - ASSERT_TRUE(std::find(results.begin(), results.end(), "HELLO VORLD") != results.end()); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// EventProcess test -/////////////////////////////////////////////////////////////////////////////////////////////////// -TYPED_TEST_P(EventStreamTest, EventProcess) -{ - using D = typename EventProcess::MyDomain; - - std::vector results; - - auto in1 = MakeEventSource(); - auto in2 = MakeEventSource(); - - auto merged = Merge(in1, in2); - int callCount = 0; - - auto processed = Process(merged, - [&] (EventRange range, EventEmitter out) - { - for (const auto& e : range) - { - *out = 0.1f * e; - *out = 1.5f * e; - } - - callCount++; - }); - - Observe(processed, - [&] (float s) - { - results.push_back(s); - }); - - DoTransaction([&] { - in1 << 10 << 20; - }); - - in2 << 30; - - ASSERT_EQ(results.size(), 6); - ASSERT_EQ(callCount, 2); - - ASSERT_EQ(results[0], 1.0f); - ASSERT_EQ(results[1], 15.0f); - ASSERT_EQ(results[2], 2.0f); - ASSERT_EQ(results[3], 30.0f); - ASSERT_EQ(results[4], 3.0f); - ASSERT_EQ(results[5], 45.0f); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -REGISTER_TYPED_TEST_CASE_P -( - EventStreamTest, - EventSources, - EventMerge1, - EventMerge2, - EventMerge3, - EventFilter, - EventTransform, - EventProcess -); - -} // ~namespace diff --git a/tests/src/EventStreamTestQ.cpp b/tests/src/EventStreamTestQ.cpp deleted file mode 100644 index 26d07507..00000000 --- a/tests/src/EventStreamTestQ.cpp +++ /dev/null @@ -1,29 +0,0 @@ - -// Copyright Sebastian Jeckel 2017. -// 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 "EventStreamTest.h" -#include "TestUtil.h" - -#include "react/engine/PulsecountEngine.h" -#include "react/engine/ToposortEngine.h" -#include "react/engine/SubtreeEngine.h" - -/////////////////////////////////////////////////////////////////////////////////////////////////// -namespace { - -using namespace react; - -using P1 = DomainParams; -using P2 = DomainParams; -using P3 = DomainParams; -using P4 = DomainParams; - -INSTANTIATE_TYPED_TEST_CASE_P(SeqToposortQ, EventStreamTest, P1); -INSTANTIATE_TYPED_TEST_CASE_P(ParToposortQ, EventStreamTest, P2); -INSTANTIATE_TYPED_TEST_CASE_P(PulsecountQ, EventStreamTest, P3); -INSTANTIATE_TYPED_TEST_CASE_P(SubtreeQ, EventStreamTest, P4); - -} // ~namespace \ No newline at end of file diff --git a/tests/src/ObserverTestQ.cpp b/tests/src/ObserverTestQ.cpp deleted file mode 100644 index 4dfe55f6..00000000 --- a/tests/src/ObserverTestQ.cpp +++ /dev/null @@ -1,29 +0,0 @@ - -// Copyright Sebastian Jeckel 2017. -// 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 "ObserverTest.h" -#include "TestUtil.h" - -#include "react/engine/PulsecountEngine.h" -#include "react/engine/ToposortEngine.h" -#include "react/engine/SubtreeEngine.h" - -/////////////////////////////////////////////////////////////////////////////////////////////////// -namespace { - -using namespace react; - -using P1 = DomainParams; -using P2 = DomainParams; -using P3 = DomainParams; -using P4 = DomainParams; - -INSTANTIATE_TYPED_TEST_CASE_P(SeqToposortQ, ObserverTest, P1); -INSTANTIATE_TYPED_TEST_CASE_P(ParToposortQ, ObserverTest, P2); -INSTANTIATE_TYPED_TEST_CASE_P(PulsecountQ, ObserverTest, P3); -INSTANTIATE_TYPED_TEST_CASE_P(SubtreeQ, ObserverTest, P4); - -} // ~namespace \ No newline at end of file diff --git a/tests/src/OperationsTest.h b/tests/src/OperationsTest.h deleted file mode 100644 index c7fb6d3f..00000000 --- a/tests/src/OperationsTest.h +++ /dev/null @@ -1,971 +0,0 @@ - -// Copyright Sebastian Jeckel 2017. -// 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) - -#pragma once - -#include "gtest/gtest.h" - -#include -#include -#include - -#include "react/Domain.h" -#include "react/Signal.h" -#include "react/Event.h" -#include "react/Observer.h" -#include "react/Algorithm.h" - -/////////////////////////////////////////////////////////////////////////////////////////////////// -namespace { - -using namespace react; -using namespace std; - -template -struct Incrementer { T operator()(Token, T v) const { return v+1; } }; - -template -struct Decrementer { T operator()(Token, T v) const { return v-1; } }; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// EventStreamTest fixture -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -class OperationsTest : public testing::Test -{ -public: - template - class MyEngine : public TParams::template EngineT {}; - - REACTIVE_DOMAIN(MyDomain, TParams::mode, MyEngine) -}; - -TYPED_TEST_CASE_P(OperationsTest); - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Iterate1 test -/////////////////////////////////////////////////////////////////////////////////////////////////// -TYPED_TEST_P(OperationsTest, Iterate1) -{ - using D = typename Iterate1::MyDomain; - - auto numSrc = MakeEventSource(); - auto numFold = Iterate(numSrc, 0, [] (int d, int v) { - return v + d; - }); - - for (auto i=1; i<=100; i++) - { - numSrc << i; - } - - ASSERT_EQ(numFold(), 5050); - - auto charSrc = MakeEventSource(); - auto strFold = Iterate(charSrc, string(""), [] (char c, string s) { - return s + c; - }); - - charSrc << 'T' << 'e' << 's' << 't'; - - ASSERT_EQ(strFold(), "Test"); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Iterate2 test -/////////////////////////////////////////////////////////////////////////////////////////////////// -TYPED_TEST_P(OperationsTest, Iterate2) -{ - using D = typename Iterate2::MyDomain; - - auto numSrc = MakeEventSource(); - auto numFold = Iterate(numSrc, 0, [] (int d, int v) { - return v + d; - }); - - int c = 0; - - Observe(numFold, [&] (int v) { - c++; - ASSERT_EQ(v, 5050); - }); - - DoTransaction([&] { - for (auto i=1; i<=100; i++) - numSrc << i; - }); - - ASSERT_EQ(numFold(), 5050); - ASSERT_EQ(c, 1); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Iterate3 test -/////////////////////////////////////////////////////////////////////////////////////////////////// -TYPED_TEST_P(OperationsTest, Iterate3) -{ - using D = typename Iterate3::MyDomain; - - auto trigger = MakeEventSource(); - - { - auto inc = Iterate(trigger, 0, Incrementer{}); - for (auto i=1; i<=100; i++) - trigger.Emit(); - - ASSERT_EQ(inc(), 100); - } - - { - auto dec = Iterate(trigger, 100, Decrementer{}); - for (auto i=1; i<=100; i++) - trigger.Emit(); - - ASSERT_EQ(dec(), 0); - } -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Monitor1 -/////////////////////////////////////////////////////////////////////////////////////////////////// -TYPED_TEST_P(OperationsTest, Monitor1) -{ - using D = typename Monitor1::MyDomain; - - auto target = MakeVar(10); - - vector results; - - auto filterFunc = [] (int v) { - return v > 10; - }; - - auto obs = Observe(Monitor(target).Filter(filterFunc), [&] (int v) { - results.push_back(v); - }); - - target <<= 10; - target <<= 20; - target <<= 20; - target <<= 10; - - ASSERT_EQ(results.size(), 1); - ASSERT_EQ(results[0], 20); - - obs.Detach(); - - target <<= 100; - - ASSERT_EQ(results.size(), 1); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Hold1 -/////////////////////////////////////////////////////////////////////////////////////////////////// -TYPED_TEST_P(OperationsTest, Hold1) -{ - using D = typename Hold1::MyDomain; - - auto src = MakeEventSource(); - - auto h = Hold(src, 0); - - ASSERT_EQ(h(), 0); - - src << 10; - - ASSERT_EQ(h(), 10); - - src << 20 << 30; - - ASSERT_EQ(h(), 30); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Hold1 -/////////////////////////////////////////////////////////////////////////////////////////////////// -TYPED_TEST_P(OperationsTest, Pulse1) -{ - using D = typename Pulse1::MyDomain; - - auto trigger = MakeEventSource(); - auto target = MakeVar(10); - - vector results; - - auto p = Pulse(trigger, target); - - Observe(p, [&] (int v) { - results.push_back(v); - }); - - target <<= 10; - trigger.Emit(); - - ASSERT_EQ(results[0], 10); - - target <<= 20; - trigger.Emit(); - - ASSERT_EQ(results[1], 20); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Snapshot1 -/////////////////////////////////////////////////////////////////////////////////////////////////// -TYPED_TEST_P(OperationsTest, Snapshot1) -{ - using D = typename Snapshot1::MyDomain; - - auto trigger = MakeEventSource(); - auto target = MakeVar(10); - - auto snap = Snapshot(trigger, target); - - target <<= 10; - trigger.Emit(); - target <<= 20; - - ASSERT_EQ(snap(), 10); - - target <<= 20; - trigger.Emit(); - target <<= 30; - - ASSERT_EQ(snap(), 20); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// IterateByRef1 test -/////////////////////////////////////////////////////////////////////////////////////////////////// -TYPED_TEST_P(OperationsTest, IterateByRef1) -{ - using D = typename IterateByRef1::MyDomain; - - auto src = MakeEventSource(); - auto f = Iterate( - src, - std::vector(), - [] (int d, std::vector& v) { - v.push_back(d); - }); - - // Push - for (auto i=1; i<=100; i++) - src << i; - - ASSERT_EQ(f().size(), 100); - - // Check - for (auto i=1; i<=100; i++) - ASSERT_EQ(f()[i-1], i); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// IterateByRef2 test -/////////////////////////////////////////////////////////////////////////////////////////////////// -TYPED_TEST_P(OperationsTest, IterateByRef2) -{ - using D = typename IterateByRef2::MyDomain; - - auto src = MakeEventSource(); - auto x = Iterate( - src, - std::vector(), - [] (Token, std::vector& v) { - v.push_back(123); - }); - - // Push - for (auto i=0; i<100; i++) - src.Emit(); - - ASSERT_EQ(x().size(), 100); - - // Check - for (auto i=0; i<100; i++) - ASSERT_EQ(x()[i], 123); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// SyncedTransform1 test -/////////////////////////////////////////////////////////////////////////////////////////////////// -TYPED_TEST_P(OperationsTest, SyncedTransform1) -{ - using D = typename SyncedTransform1::MyDomain; - - auto in1 = MakeVar(1); - auto in2 = MakeVar(1); - - auto sum = in1 + in2; - auto prod = in1 * in2; - auto diff = in1 - in2; - - auto src1 = MakeEventSource(); - auto src2 = MakeEventSource(); - - auto out1 = Transform(src1, With(sum,prod,diff), [] (Token, int sum, int prod, int diff) { - return make_tuple(sum, prod, diff); - }); - - auto out2 = Transform(src2, With(sum,prod,diff), [] (int e, int sum, int prod, int diff) { - return make_tuple(e, sum, prod, diff); - }); - - int obsCount1 = 0; - int obsCount2 = 0; - - { - auto obs1 = Observe(out1, [&] (const tuple& t) { - ++obsCount1; - - ASSERT_EQ(get<0>(t), 33); - ASSERT_EQ(get<1>(t), 242); - ASSERT_EQ(get<2>(t), 11); - }); - - auto obs2 = Observe(out2, [&] (const tuple& t) { - ++obsCount2; - - ASSERT_EQ(get<0>(t), 42); - ASSERT_EQ(get<1>(t), 33); - ASSERT_EQ(get<2>(t), 242); - ASSERT_EQ(get<3>(t), 11); - }); - - in1 <<= 22; - in2 <<= 11; - - src1.Emit(); - src2.Emit(42); - - ASSERT_EQ(obsCount1, 1); - ASSERT_EQ(obsCount2, 1); - - obs1.Detach(); - obs2.Detach(); - } - - { - auto obs1 = Observe(out1, [&] (const tuple& t) { - ++obsCount1; - - ASSERT_EQ(get<0>(t), 330); - ASSERT_EQ(get<1>(t), 24200); - ASSERT_EQ(get<2>(t), 110); - }); - - auto obs2 = Observe(out2, [&] (const tuple& t) { - ++obsCount2; - - ASSERT_EQ(get<0>(t), 420); - ASSERT_EQ(get<1>(t), 330); - ASSERT_EQ(get<2>(t), 24200); - ASSERT_EQ(get<3>(t), 110); - }); - - in1 <<= 220; - in2 <<= 110; - - src1.Emit(); - src2.Emit(420); - - ASSERT_EQ(obsCount1, 2); - ASSERT_EQ(obsCount2, 2); - - obs1.Detach(); - obs2.Detach(); - } -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// SyncedIterate1 test -/////////////////////////////////////////////////////////////////////////////////////////////////// -TYPED_TEST_P(OperationsTest, SyncedIterate1) -{ - using D = typename SyncedIterate1::MyDomain; - - auto in1 = MakeVar(1); - auto in2 = MakeVar(1); - - auto op1 = in1 + in2; - auto op2 = (in1 + in2) * 10; - - auto src1 = MakeEventSource(); - auto src2 = MakeEventSource(); - - auto out1 = Iterate( - src1, - make_tuple(0,0), - With(op1,op2), - [] (Token, const tuple& t, int op1, int op2) { - return make_tuple(get<0>(t) + op1, get<1>(t) + op2); - }); - - auto out2 = Iterate( - src2, - make_tuple(0,0,0), - With(op1,op2), - [] (int e, const tuple& t, int op1, int op2) { - return make_tuple(get<0>(t) + e, get<1>(t) + op1, get<2>(t) + op2); - }); - - int obsCount1 = 0; - int obsCount2 = 0; - - { - auto obs1 = Observe(out1, [&] (const tuple& t) { - ++obsCount1; - - ASSERT_EQ(get<0>(t), 33); - ASSERT_EQ(get<1>(t), 330); - }); - - auto obs2 = Observe(out2, [&] (const tuple& t) { - ++obsCount2; - - ASSERT_EQ(get<0>(t), 42); - ASSERT_EQ(get<1>(t), 33); - ASSERT_EQ(get<2>(t), 330); - }); - - in1 <<= 22; - in2 <<= 11; - - src1.Emit(); - src2.Emit(42); - - ASSERT_EQ(obsCount1, 1); - ASSERT_EQ(obsCount2, 1); - - obs1.Detach(); - obs2.Detach(); - } - - { - auto obs1 = Observe(out1, [&] (const tuple& t) { - ++obsCount1; - - ASSERT_EQ(get<0>(t), 33 + 330); - ASSERT_EQ(get<1>(t), 330 + 3300); - }); - - auto obs2 = Observe(out2, [&] (const tuple& t) { - ++obsCount2; - - ASSERT_EQ(get<0>(t), 42 + 420); - ASSERT_EQ(get<1>(t), 33 + 330); - ASSERT_EQ(get<2>(t), 330 + 3300); - }); - - in1 <<= 220; - in2 <<= 110; - - src1.Emit(); - src2.Emit(420); - - ASSERT_EQ(obsCount1, 2); - ASSERT_EQ(obsCount2, 2); - - obs1.Detach(); - obs2.Detach(); - } -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// SyncedIterate2 test (by ref) -/////////////////////////////////////////////////////////////////////////////////////////////////// -TYPED_TEST_P(OperationsTest, SyncedIterate2) -{ - using D = typename SyncedIterate2::MyDomain; - - auto in1 = MakeVar(1); - auto in2 = MakeVar(1); - - auto op1 = in1 + in2; - auto op2 = (in1 + in2) * 10; - - auto src1 = MakeEventSource(); - auto src2 = MakeEventSource(); - - auto out1 = Iterate( - src1, - vector{}, - With(op1,op2), - [] (Token, vector& v, int op1, int op2) -> void { - v.push_back(op1); - v.push_back(op2); - }); - - auto out2 = Iterate( - src2, - vector{}, - With(op1,op2), - [] (int e, vector& v, int op1, int op2) -> void { - v.push_back(e); - v.push_back(op1); - v.push_back(op2); - }); - - int obsCount1 = 0; - int obsCount2 = 0; - - { - auto obs1 = Observe(out1, [&] (const vector& v) { - ++obsCount1; - - ASSERT_EQ(v.size(), 2); - - ASSERT_EQ(v[0], 33); - ASSERT_EQ(v[1], 330); - }); - - auto obs2 = Observe(out2, [&] (const vector& v) { - ++obsCount2; - - ASSERT_EQ(v.size(), 3); - - ASSERT_EQ(v[0], 42); - ASSERT_EQ(v[1], 33); - ASSERT_EQ(v[2], 330); - }); - - in1 <<= 22; - in2 <<= 11; - - src1.Emit(); - src2.Emit(42); - - ASSERT_EQ(obsCount1, 1); - ASSERT_EQ(obsCount2, 1); - - obs1.Detach(); - obs2.Detach(); - } - - { - auto obs1 = Observe(out1, [&] (const vector& v) { - ++obsCount1; - - ASSERT_EQ(v.size(), 4); - - ASSERT_EQ(v[0], 33); - ASSERT_EQ(v[1], 330); - ASSERT_EQ(v[2], 330); - ASSERT_EQ(v[3], 3300); - }); - - auto obs2 = Observe(out2, [&] (const vector& v) { - ++obsCount2; - - ASSERT_EQ(v.size(), 6); - - ASSERT_EQ(v[0], 42); - ASSERT_EQ(v[1], 33); - ASSERT_EQ(v[2], 330); - - ASSERT_EQ(v[3], 420); - ASSERT_EQ(v[4], 330); - ASSERT_EQ(v[5], 3300); - }); - - in1 <<= 220; - in2 <<= 110; - - src1.Emit(); - src2.Emit(420); - - ASSERT_EQ(obsCount1, 2); - ASSERT_EQ(obsCount2, 2); - - obs1.Detach(); - obs2.Detach(); - } -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// SyncedIterate3 test (event range) -/////////////////////////////////////////////////////////////////////////////////////////////////// -TYPED_TEST_P(OperationsTest, SyncedIterate3) -{ - using D = typename SyncedIterate3::MyDomain; - - auto in1 = MakeVar(1); - auto in2 = MakeVar(1); - - auto op1 = in1 + in2; - auto op2 = (in1 + in2) * 10; - - auto src1 = MakeEventSource(); - auto src2 = MakeEventSource(); - - auto out1 = Iterate( - src1, - make_tuple(0,0), - With(op1,op2), - [] (EventRange range, const tuple& t, int op1, int op2) { - return make_tuple( - get<0>(t) + (op1 * range.Size()), - get<1>(t) + (op2 * range.Size())); - }); - - auto out2 = Iterate( - src2, - make_tuple(0,0,0), - With(op1,op2), - [] (EventRange range, const tuple& t, int op1, int op2) { - int sum = 0; - for (const auto& e : range) - sum += e; - - return make_tuple( - get<0>(t) + sum, - get<1>(t) + (op1 * range.Size()), - get<2>(t) + (op2 * range.Size())); - }); - - int obsCount1 = 0; - int obsCount2 = 0; - - { - auto obs1 = Observe(out1, [&] (const tuple& t) { - ++obsCount1; - - ASSERT_EQ(get<0>(t), 33); - ASSERT_EQ(get<1>(t), 330); - }); - - auto obs2 = Observe(out2, [&] (const tuple& t) { - ++obsCount2; - - ASSERT_EQ(get<0>(t), 42); - ASSERT_EQ(get<1>(t), 33); - ASSERT_EQ(get<2>(t), 330); - }); - - in1 <<= 22; - in2 <<= 11; - - src1.Emit(); - src2.Emit(42); - - ASSERT_EQ(obsCount1, 1); - ASSERT_EQ(obsCount2, 1); - - obs1.Detach(); - obs2.Detach(); - } - - { - auto obs1 = Observe(out1, [&] (const tuple& t) { - ++obsCount1; - - ASSERT_EQ(get<0>(t), 33 + 330); - ASSERT_EQ(get<1>(t), 330 + 3300); - }); - - auto obs2 = Observe(out2, [&] (const tuple& t) { - ++obsCount2; - - ASSERT_EQ(get<0>(t), 42 + 420); - ASSERT_EQ(get<1>(t), 33 + 330); - ASSERT_EQ(get<2>(t), 330 + 3300); - }); - - in1 <<= 220; - in2 <<= 110; - - src1.Emit(); - src2.Emit(420); - - ASSERT_EQ(obsCount1, 2); - ASSERT_EQ(obsCount2, 2); - - obs1.Detach(); - obs2.Detach(); - } -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// SyncedIterate4 test (event range, by ref) -/////////////////////////////////////////////////////////////////////////////////////////////////// -TYPED_TEST_P(OperationsTest, SyncedIterate4) -{ - using D = typename SyncedIterate4::MyDomain; - - auto in1 = MakeVar(1); - auto in2 = MakeVar(1); - - auto op1 = in1 + in2; - auto op2 = (in1 + in2) * 10; - - auto src1 = MakeEventSource(); - auto src2 = MakeEventSource(); - - auto out1 = Iterate( - src1, - vector{}, - With(op1,op2), - [] (EventRange range, vector& v, int op1, int op2) -> void { - for (const auto& e : range) - { - v.push_back(op1); - v.push_back(op2); - } - }); - - auto out2 = Iterate( - src2, - vector{}, - With(op1,op2), - [] (EventRange range, vector& v, int op1, int op2) -> void { - for (const auto& e : range) - { - v.push_back(e); - v.push_back(op1); - v.push_back(op2); - } - }); - - int obsCount1 = 0; - int obsCount2 = 0; - - { - auto obs1 = Observe(out1, [&] (const vector& v) { - ++obsCount1; - - ASSERT_EQ(v.size(), 2); - - ASSERT_EQ(v[0], 33); - ASSERT_EQ(v[1], 330); - }); - - auto obs2 = Observe(out2, [&] (const vector& v) { - ++obsCount2; - - ASSERT_EQ(v.size(), 3); - - ASSERT_EQ(v[0], 42); - ASSERT_EQ(v[1], 33); - ASSERT_EQ(v[2], 330); - }); - - in1 <<= 22; - in2 <<= 11; - - src1.Emit(); - src2.Emit(42); - - ASSERT_EQ(obsCount1, 1); - ASSERT_EQ(obsCount2, 1); - - obs1.Detach(); - obs2.Detach(); - } - - { - auto obs1 = Observe(out1, [&] (const vector& v) { - ++obsCount1; - - ASSERT_EQ(v.size(), 4); - - ASSERT_EQ(v[0], 33); - ASSERT_EQ(v[1], 330); - ASSERT_EQ(v[2], 330); - ASSERT_EQ(v[3], 3300); - }); - - auto obs2 = Observe(out2, [&] (const vector& v) { - ++obsCount2; - - ASSERT_EQ(v.size(), 6); - - ASSERT_EQ(v[0], 42); - ASSERT_EQ(v[1], 33); - ASSERT_EQ(v[2], 330); - - ASSERT_EQ(v[3], 420); - ASSERT_EQ(v[4], 330); - ASSERT_EQ(v[5], 3300); - }); - - in1 <<= 220; - in2 <<= 110; - - src1.Emit(); - src2.Emit(420); - - ASSERT_EQ(obsCount1, 2); - ASSERT_EQ(obsCount2, 2); - - obs1.Detach(); - obs2.Detach(); - } -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// EventFilter1 -/////////////////////////////////////////////////////////////////////////////////////////////////// -TYPED_TEST_P(OperationsTest, SyncedEventFilter1) -{ - using D = typename SyncedEventFilter1::MyDomain; - - using std::string; - - std::queue results; - - auto in = MakeEventSource(); - - auto sig1 = MakeVar(1338); - auto sig2 = MakeVar(1336); - - auto filtered = Filter( - in, - With(sig1, sig2), - [] (const string& s, int sig1, int sig2) { - return s == "Hello World" && sig1 > sig2; - }); - - - Observe(filtered, [&] (const string& s) - { - results.push(s); - }); - - in << string("Hello Worlt") << string("Hello World") << string("Hello Vorld"); - sig1 <<= 1335; - in << string("Hello Vorld"); - - ASSERT_FALSE(results.empty()); - ASSERT_EQ(results.front(), "Hello World"); - results.pop(); - - ASSERT_TRUE(results.empty()); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// SyncedEventTransform1 -/////////////////////////////////////////////////////////////////////////////////////////////////// -TYPED_TEST_P(OperationsTest, SyncedEventTransform1) -{ - using D = typename SyncedEventTransform1::MyDomain; - - using std::string; - - std::vector results; - - auto in1 = MakeEventSource(); - auto in2 = MakeEventSource(); - - auto merged = Merge(in1, in2); - - auto first = MakeVar(string("Ace")); - auto last = MakeVar(string("McSteele")); - - auto transformed = Transform( - merged, - With(first, last), - [] (string s, const string& first, const string& last) -> string { - std::transform(s.begin(), s.end(), s.begin(), ::toupper); - s += string(", ") + first + string(" ") + last; - return s; - }); - - Observe(transformed, [&] (const string& s) { - results.push_back(s); - }); - - in1 << string("Hello Worlt") << string("Hello World"); - - DoTransaction([&] { - in2 << string("Hello Vorld"); - first.Set(string("Alice")); - last.Set(string("Anderson")); - }); - - ASSERT_EQ(results.size(), 3); - ASSERT_TRUE(std::find(results.begin(), results.end(), "HELLO WORLT, Ace McSteele") != results.end()); - ASSERT_TRUE(std::find(results.begin(), results.end(), "HELLO WORLD, Ace McSteele") != results.end()); - ASSERT_TRUE(std::find(results.begin(), results.end(), "HELLO VORLD, Alice Anderson") != results.end()); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// SyncedEventProcess1 -/////////////////////////////////////////////////////////////////////////////////////////////////// -TYPED_TEST_P(OperationsTest, SyncedEventProcess1) -{ - using D = typename SyncedEventProcess1::MyDomain; - - std::vector results; - - auto in1 = MakeEventSource(); - auto in2 = MakeEventSource(); - - auto mult = MakeVar(10); - - auto merged = Merge(in1, in2); - int callCount = 0; - - auto processed = Process(merged, - With(mult), - [&] (EventRange range, EventEmitter out, int mult) - { - for (const auto& e : range) - { - *out = 0.1f * e * mult; - *out = 1.5f * e * mult; - } - - callCount++; - }); - - Observe(processed, - [&] (float s) - { - results.push_back(s); - }); - - DoTransaction([&] { - in1 << 10 << 20; - }); - - in2 << 30; - - ASSERT_EQ(results.size(), 6); - ASSERT_EQ(callCount, 2); - - ASSERT_EQ(results[0], 10.0f); - ASSERT_EQ(results[1], 150.0f); - ASSERT_EQ(results[2], 20.0f); - ASSERT_EQ(results[3], 300.0f); - ASSERT_EQ(results[4], 30.0f); - ASSERT_EQ(results[5], 450.0f); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -REGISTER_TYPED_TEST_CASE_P -( - OperationsTest, - Iterate1, - Iterate2, - Iterate3, - Monitor1, - Hold1, - Pulse1, - Snapshot1, - IterateByRef1, - IterateByRef2, - SyncedTransform1, - SyncedIterate1, - SyncedIterate2, - SyncedIterate3, - SyncedIterate4, - SyncedEventFilter1, - SyncedEventTransform1, - SyncedEventProcess1 -); - -} // ~namespace diff --git a/tests/src/OperationsTestQ.cpp b/tests/src/OperationsTestQ.cpp deleted file mode 100644 index 576c0752..00000000 --- a/tests/src/OperationsTestQ.cpp +++ /dev/null @@ -1,29 +0,0 @@ - -// Copyright Sebastian Jeckel 2017. -// 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 "OperationsTest.h" -#include "TestUtil.h" - -#include "react/engine/PulsecountEngine.h" -#include "react/engine/ToposortEngine.h" -#include "react/engine/SubtreeEngine.h" - -/////////////////////////////////////////////////////////////////////////////////////////////////// -namespace { - -using namespace react; - -using P1 = DomainParams; -using P2 = DomainParams; -using P3 = DomainParams; -using P4 = DomainParams; - -INSTANTIATE_TYPED_TEST_CASE_P(SeqToposortQ, OperationsTest, P1); -INSTANTIATE_TYPED_TEST_CASE_P(ParToposortQ, OperationsTest, P2); -INSTANTIATE_TYPED_TEST_CASE_P(PulsecountQ, OperationsTest, P3); -INSTANTIATE_TYPED_TEST_CASE_P(SubtreeQ, OperationsTest, P4); - -} // ~namespace \ No newline at end of file diff --git a/tests/src/ParallelizationTest.cpp b/tests/src/ParallelizationTest.cpp deleted file mode 100644 index 6054092a..00000000 --- a/tests/src/ParallelizationTest.cpp +++ /dev/null @@ -1,12 +0,0 @@ - -// Copyright Sebastian Jeckel 2017. -// 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) - - -/////////////////////////////////////////////////////////////////////////////////////////////////// -namespace { - - -} // ~namespace \ No newline at end of file diff --git a/tests/src/ParallelizationTest.h b/tests/src/ParallelizationTest.h deleted file mode 100644 index 145c730c..00000000 --- a/tests/src/ParallelizationTest.h +++ /dev/null @@ -1,63 +0,0 @@ - -// Copyright Sebastian Jeckel 2017. -// 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) - -#pragma once - -#include "gtest/gtest.h" - -#include "react/Domain.h" -#include "react/Signal.h" -#include "react/Event.h" -#include "react/Observer.h" -#include "react/Algorithm.h" - -/////////////////////////////////////////////////////////////////////////////////////////////////// -namespace { - -using namespace react; -using namespace std; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// ParallelizationTest fixture -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -class ParallelizationTest : public testing::Test -{ -public: - template - class MyEngine : public TParams::template EngineT {}; - - REACTIVE_DOMAIN(MyDomain, TParams::mode, MyEngine) -}; - -TYPED_TEST_CASE_P(ParallelizationTest); - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Iterate1 test -/////////////////////////////////////////////////////////////////////////////////////////////////// -TYPED_TEST_P(ParallelizationTest, WeightHint1) -{ - using D = typename WeightHint1::MyDomain; - - auto sig = MakeVar(0); - auto evn = MakeEventSource(); - auto cont = MakeContinuation(sig, [] (int v) {}); - auto obs = Observe(evn, [] (int v) {}); - - sig.SetWeightHint(WeightHint::heavy); - evn.SetWeightHint(WeightHint::automatic); - cont.SetWeightHint(WeightHint::light); - obs.SetWeightHint(WeightHint::automatic); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -REGISTER_TYPED_TEST_CASE_P -( - ParallelizationTest, - WeightHint1 -); - -} // ~namespace diff --git a/tests/src/SignalTest.h b/tests/src/SignalTest.h deleted file mode 100644 index 69ae81de..00000000 --- a/tests/src/SignalTest.h +++ /dev/null @@ -1,664 +0,0 @@ - -// Copyright Sebastian Jeckel 2017. -// 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) - -#pragma once - -#include "gtest/gtest.h" - -#include -#include - -#include "react/Domain.h" -#include "react/Signal.h" - -/////////////////////////////////////////////////////////////////////////////////////////////////// -namespace { - -using namespace react; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// SignalTest fixture -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -class SignalTest : public testing::Test -{ -public: - template - class MyEngine : public TParams::template EngineT {}; - - REACTIVE_DOMAIN(MyDomain, TParams::mode, MyEngine) -}; - -TYPED_TEST_CASE_P(SignalTest); - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// MakeVars test -/////////////////////////////////////////////////////////////////////////////////////////////////// -TYPED_TEST_P(SignalTest, MakeVars) -{ - using D = typename MakeVars::MyDomain; - - auto v1 = MakeVar(1); - auto v2 = MakeVar(2); - auto v3 = MakeVar(3); - auto v4 = MakeVar(4); - - ASSERT_EQ(v1(),1); - ASSERT_EQ(v2(),2); - ASSERT_EQ(v3(),3); - ASSERT_EQ(v4(),4); - - v1 <<= 10; - v2 <<= 20; - v3 <<= 30; - v4 <<= 40; - - ASSERT_EQ(v1(),10); - ASSERT_EQ(v2(),20); - ASSERT_EQ(v3(),30); - ASSERT_EQ(v4(),40); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Signals1 test -/////////////////////////////////////////////////////////////////////////////////////////////////// -TYPED_TEST_P(SignalTest, Signals1) -{ - using D = typename Signals1::MyDomain; - - auto v1 = MakeVar(1); - auto v2 = MakeVar(2); - auto v3 = MakeVar(3); - auto v4 = MakeVar(4); - - auto s1 = MakeSignal(With(v1,v2), [] (int a, int b) { - return a + b; - }); - - auto s2 = MakeSignal(With(v3,v4), [] (int a, int b) { - return a + b; - }); - - auto s3 = s1 + s2; - - ASSERT_EQ(s1(),3); - ASSERT_EQ(s2(),7); - ASSERT_EQ(s3(),10); - - v1 <<= 10; - v2 <<= 20; - v3 <<= 30; - v4 <<= 40; - - ASSERT_EQ(s1(),30); - ASSERT_EQ(s2(),70); - ASSERT_EQ(s3(),100); - - bool b = false; - - b = IsSignal::value; - ASSERT_TRUE(b); - - b = IsSignal::value; - ASSERT_TRUE(b); - - b = IsSignal::value; - ASSERT_TRUE(b); - - b = IsSignal::value; - ASSERT_FALSE(b); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Signals2 test -/////////////////////////////////////////////////////////////////////////////////////////////////// -TYPED_TEST_P(SignalTest, Signals2) -{ - using D = typename Signals2::MyDomain; - - auto a1 = MakeVar(1); - auto a2 = MakeVar(1); - - auto b1 = a1 + 0; - auto b2 = a1 + a2; - auto b3 = a2 + 0; - - auto c1 = b1 + b2; - auto c2 = b2 + b3; - - auto result = c1 + c2; - - int observeCount = 0; - - Observe(result, [&observeCount] (int v) - { - observeCount++; - if (observeCount == 1) - ASSERT_EQ(v,9); - else - ASSERT_EQ(v,12); - }); - - ASSERT_EQ(a1(),1); - ASSERT_EQ(a2(),1); - - ASSERT_EQ(b1(),1); - ASSERT_EQ(b2(),2); - ASSERT_EQ(b3(),1); - - ASSERT_EQ(c1(),3); - ASSERT_EQ(c2(),3); - - ASSERT_EQ(result(),6); - - a1 <<= 2; - - ASSERT_EQ(observeCount,1); - - ASSERT_EQ(a1(),2); - ASSERT_EQ(a2(),1); - - ASSERT_EQ(b1(),2); - ASSERT_EQ(b2(),3); - ASSERT_EQ(b3(),1); - - ASSERT_EQ(c1(),5); - ASSERT_EQ(c2(),4); - - ASSERT_EQ(result(),9); - - a2 <<= 2; - - ASSERT_EQ(observeCount,2); - - ASSERT_EQ(a1(),2); - ASSERT_EQ(a2(),2); - - ASSERT_EQ(b1(),2); - ASSERT_EQ(b2(),4); - ASSERT_EQ(b3(),2); - - ASSERT_EQ(c1(),6); - ASSERT_EQ(c2(),6); - - ASSERT_EQ(result(),12); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Signals3 test -/////////////////////////////////////////////////////////////////////////////////////////////////// -TYPED_TEST_P(SignalTest, Signals3) -{ - using D = typename Signals3::MyDomain; - - auto a1 = MakeVar(1); - auto a2 = MakeVar(1); - - auto b1 = a1 + 0; - auto b2 = a1 + a2; - auto b3 = a2 + 0; - - auto c1 = b1 + b2; - auto c2 = b2 + b3; - - auto result = c1 + c2; - - int observeCount = 0; - - Observe(result, [&observeCount] (int v) - { - observeCount++; - ASSERT_EQ(v,12); - }); - - ASSERT_EQ(a1(),1); - ASSERT_EQ(a2(),1); - - ASSERT_EQ(b1(),1); - ASSERT_EQ(b2(),2); - ASSERT_EQ(b3(),1); - - ASSERT_EQ(c1(),3); - ASSERT_EQ(c2(),3); - - ASSERT_EQ(result(),6); - - DoTransaction([&] { - a1 <<= 2; - a2 <<= 2; - }); - - ASSERT_EQ(observeCount,1); - - ASSERT_EQ(a1(),2); - ASSERT_EQ(a2(),2); - - ASSERT_EQ(b1(),2); - ASSERT_EQ(b2(),4); - ASSERT_EQ(b3(),2); - - ASSERT_EQ(c1(),6); - ASSERT_EQ(c2(),6); - - ASSERT_EQ(result(),12); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Signals4 test -/////////////////////////////////////////////////////////////////////////////////////////////////// -TYPED_TEST_P(SignalTest, Signals4) -{ - using D = typename Signals4::MyDomain; - - auto a1 = MakeVar(1); - auto a2 = MakeVar(1); - - auto b1 = a1 + a2; - auto b2 = b1 + a2; - - ASSERT_EQ(a1(),1); - ASSERT_EQ(a2(),1); - - ASSERT_EQ(b1(),2); - ASSERT_EQ(b2(),3); - - a1 <<= 10; - - ASSERT_EQ(a1(),10); - ASSERT_EQ(a2(),1); - - ASSERT_EQ(b1(),11); - ASSERT_EQ(b2(),12); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// FunctionBind1 test -/////////////////////////////////////////////////////////////////////////////////////////////////// -TYPED_TEST_P(SignalTest, FunctionBind1) -{ - using D = typename FunctionBind1::MyDomain; - - auto v1 = MakeVar(2); - auto v2 = MakeVar(30); - auto v3 = MakeVar(10); - - auto signal = (v1, v2, v3) ->* [=] (int a, int b, int c) -> int - { - return a * b * c; - }; - - ASSERT_EQ(signal(),600); - v3 <<= 100; - ASSERT_EQ(signal(),6000); -} - -int myfunc(int a, int b) { return a + b; } -float myfunc2(int a) { return a / 2.0f; } -float myfunc3(float a, float b) { return a * b; } - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// FunctionBind2 test -/////////////////////////////////////////////////////////////////////////////////////////////////// -TYPED_TEST_P(SignalTest, FunctionBind2) -{ - using D = typename FunctionBind2::MyDomain; - - auto a = MakeVar(1); - auto b = MakeVar(1); - - auto c = ((a+b), (a+100)) ->* &myfunc; - auto d = c ->* &myfunc2; - auto e = (d,d) ->* &myfunc3; - auto f = -e + 100; - - ASSERT_EQ(c(),103); - ASSERT_EQ(d(),51.5f); - ASSERT_EQ(e(),2652.25f); - ASSERT_EQ(f(),-2552.25); - - a <<= 10; - - ASSERT_EQ(c(),121); - ASSERT_EQ(d(),60.5f); - ASSERT_EQ(e(),3660.25f); - ASSERT_EQ(f(),-3560.25f); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Flatten1 test -/////////////////////////////////////////////////////////////////////////////////////////////////// -TYPED_TEST_P(SignalTest, Flatten1) -{ - using D = typename Flatten1::MyDomain; - - auto inner1 = MakeVar(123); - auto inner2 = MakeVar(789); - - auto outer = MakeVar(inner1); - - auto flattened = Flatten(outer); - - std::queue results; - - Observe(flattened, [&] (int v) - { - results.push(v); - }); - - ASSERT_TRUE(outer().Equals(inner1)); - ASSERT_EQ(flattened(),123); - - inner1 <<= 456; - - ASSERT_EQ(flattened(),456); - - ASSERT_EQ(results.front(), 456); - results.pop(); - ASSERT_TRUE(results.empty()); - - outer <<= inner2; - - ASSERT_TRUE(outer().Equals(inner2)); - ASSERT_EQ(flattened(),789); - - ASSERT_EQ(results.front(), 789); - results.pop(); - ASSERT_TRUE(results.empty()); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Flatten2 test -/////////////////////////////////////////////////////////////////////////////////////////////////// -TYPED_TEST_P(SignalTest, Flatten2) -{ - using D = typename Flatten2::MyDomain; - - auto a0 = MakeVar(100); - - auto inner1 = MakeVar(200); - - auto a1 = MakeVar(300); - auto a2 = a1 + 0; - auto a3 = a2 + 0; - auto a4 = a3 + 0; - auto a5 = a4 + 0; - auto a6 = a5 + 0; - auto inner2 = a6 + 0; - - ASSERT_EQ(inner1(),200); - ASSERT_EQ(inner2(),300); - - auto outer = MakeVar(inner1); - - auto flattened = Flatten(outer); - - ASSERT_EQ(flattened(), 200); - - int observeCount = 0; - - Observe(flattened, [&observeCount] (int v) - { - observeCount++; - }); - - auto o1 = a0 + flattened; - auto o2 = o1 + 0; - auto o3 = o2 + 0; - auto result = o3 + 0; - - ASSERT_EQ(result(), 100 + 200); - - inner1 <<= 1234; - - ASSERT_EQ(result(), 100 + 1234); - ASSERT_EQ(observeCount, 1); - - outer <<= inner2; - - ASSERT_EQ(result(), 100 + 300); - ASSERT_EQ(observeCount, 2); - - DoTransaction([&] { - a0 <<= 5000; - a1 <<= 6000; - }); - - ASSERT_EQ(result(), 5000 + 6000); - ASSERT_EQ(observeCount, 3); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Flatten3 test -/////////////////////////////////////////////////////////////////////////////////////////////////// -TYPED_TEST_P(SignalTest, Flatten3) -{ - using D = typename Flatten3::MyDomain; - - auto inner1 = MakeVar(10); - - auto a1 = MakeVar(20); - auto a2 = a1 + 0; - auto a3 = a2 + 0; - auto inner2 = a3 + 0; - - auto outer = MakeVar(inner1); - - auto a0 = MakeVar(30); - - auto flattened = Flatten(outer); - - int observeCount = 0; - - Observe(flattened, [&observeCount] (int v) - { - observeCount++; - }); - - auto result = flattened + a0; - - ASSERT_EQ(result(), 10 + 30); - ASSERT_EQ(observeCount, 0); - - DoTransaction([&] { - inner1 <<= 1000; - a0 <<= 200000; - a1 <<= 50000; - outer <<= inner2; - }); - - ASSERT_EQ(result(), 50000 + 200000); - ASSERT_EQ(observeCount, 1); - - DoTransaction([&] { - a0 <<= 667; - a1 <<= 776; - }); - - ASSERT_EQ(result(), 776 + 667); - ASSERT_EQ(observeCount, 2); - - DoTransaction([&] { - inner1 <<= 999; - a0 <<= 888; - }); - - ASSERT_EQ(result(), 776 + 888); - ASSERT_EQ(observeCount, 2); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Flatten4 test -/////////////////////////////////////////////////////////////////////////////////////////////////// -TYPED_TEST_P(SignalTest, Flatten4) -{ - using D = typename Flatten4::MyDomain; - - std::vector results; - - auto a1 = MakeVar(100); - auto inner1 = a1 + 0; - - auto a2 = MakeVar(200); - auto inner2 = a2; - - auto a3 = MakeVar(200); - - auto outer = MakeVar(inner1); - - auto flattened = Flatten(outer); - - auto result = flattened + a3; - - Observe(result, [&] (int v) { - results.push_back(v); - }); - - DoTransaction([&] { - a3 <<= 400; - outer <<= inner2; - }); - - ASSERT_EQ(results.size(), 1); - - ASSERT_TRUE(std::find(results.begin(), results.end(), 600) != results.end()); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Member1 test -/////////////////////////////////////////////////////////////////////////////////////////////////// -TYPED_TEST_P(SignalTest, Member1) -{ - using D = typename Member1::MyDomain; - - auto outer = MakeVar(10); - auto inner = MakeVar(outer); - - auto flattened = inner.Flatten(); - - Observe(flattened, [] (int v) { - ASSERT_EQ(v, 30); - }); - - outer <<= 30; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Modify1 test -/////////////////////////////////////////////////////////////////////////////////////////////////// -TYPED_TEST_P(SignalTest, Modify1) -{ - using D = typename Modify1::MyDomain; - - using std::vector; - - auto v = MakeVar(vector{}); - - int obsCount = 0; - - Observe(v, [&] (const vector& v) { - ASSERT_EQ(v[0], 30); - ASSERT_EQ(v[1], 50); - ASSERT_EQ(v[2], 70); - - obsCount++; - }); - - v.Modify([] (vector& v) { - v.push_back(30); - v.push_back(50); - v.push_back(70); - }); - - ASSERT_EQ(obsCount, 1); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Modify2 test -/////////////////////////////////////////////////////////////////////////////////////////////////// -TYPED_TEST_P(SignalTest, Modify2) -{ - using D = typename Modify2::MyDomain; - - using std::vector; - - auto v = MakeVar(vector{}); - - int obsCount = 0; - - Observe(v, [&] (const vector& v) { - ASSERT_EQ(v[0], 30); - ASSERT_EQ(v[1], 50); - ASSERT_EQ(v[2], 70); - - obsCount++; - }); - - DoTransaction([&] { - v.Modify([] (vector& v) { - v.push_back(30); - }); - - v.Modify([] (vector& v) { - v.push_back(50); - }); - - v.Modify([] (vector& v) { - v.push_back(70); - }); - }); - - - ASSERT_EQ(obsCount, 1); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Modify3 test -/////////////////////////////////////////////////////////////////////////////////////////////////// -TYPED_TEST_P(SignalTest, Modify3) -{ - using D = typename Modify3::MyDomain; - - using std::vector; - - auto vect = MakeVar(vector{}); - - int obsCount = 0; - - Observe(vect, [&] (const vector& v) { - ASSERT_EQ(v[0], 30); - ASSERT_EQ(v[1], 50); - ASSERT_EQ(v[2], 70); - - obsCount++; - }); - - // Also terrible - DoTransaction([&] { - - vect.Set(vector{ 30, 50 }); - - vect.Modify([] (vector& v) { - v.push_back(70); - }); - }); - - ASSERT_EQ(obsCount, 1); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -REGISTER_TYPED_TEST_CASE_P -( - SignalTest, - MakeVars, - Signals1, Signals2, Signals3, Signals4, - FunctionBind1, FunctionBind2, - Flatten1, Flatten2, Flatten3, Flatten4, - Member1, - Modify1, Modify2, Modify3 - -); - -} // ~namespace diff --git a/tests/src/SignalTestQ.cpp b/tests/src/SignalTestQ.cpp deleted file mode 100644 index d91875c7..00000000 --- a/tests/src/SignalTestQ.cpp +++ /dev/null @@ -1,29 +0,0 @@ - -// Copyright Sebastian Jeckel 2017. -// 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 "SignalTest.h" -#include "TestUtil.h" - -#include "react/engine/PulsecountEngine.h" -#include "react/engine/ToposortEngine.h" -#include "react/engine/SubtreeEngine.h" - -/////////////////////////////////////////////////////////////////////////////////////////////////// -namespace { - -using namespace react; - -using P1 = DomainParams; -using P2 = DomainParams; -using P3 = DomainParams; -using P4 = DomainParams; - -INSTANTIATE_TYPED_TEST_CASE_P(SeqToposortQ, SignalTest, P1); -INSTANTIATE_TYPED_TEST_CASE_P(ParToposortQ, SignalTest, P2); -INSTANTIATE_TYPED_TEST_CASE_P(PulsecountQ, SignalTest, P3); -INSTANTIATE_TYPED_TEST_CASE_P(SubtreeQ, SignalTest, P4); - -} // ~namespace \ No newline at end of file diff --git a/tests/src/TestUtil.h b/tests/src/TestUtil.h deleted file mode 100644 index 0d7b9cb6..00000000 --- a/tests/src/TestUtil.h +++ /dev/null @@ -1,25 +0,0 @@ - -// Copyright Sebastian Jeckel 2017. -// 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) - -#pragma once - -#ifndef REACT_TESTS_TESTUTIL_H_INCLUDED -#define REACT_TESTS_TESTUTIL_H_INCLUDED - -template -< - EDomainMode m, - template class TTEngine -> -struct DomainParams -{ - static const EDomainMode mode = m; - - template - using EngineT = TTEngine; -}; - -#endif // REACT_TESTS_TESTUTIL_H_INCLUDED \ No newline at end of file diff --git a/tests/src/TransactionTest.h b/tests/src/TransactionTest.h deleted file mode 100644 index 0501a81c..00000000 --- a/tests/src/TransactionTest.h +++ /dev/null @@ -1,571 +0,0 @@ - -// Copyright Sebastian Jeckel 2017. -// 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) - -#pragma once - -#include "gtest/gtest.h" - -#include -#include -#include - -#include "react/Domain.h" -#include "react/Signal.h" -#include "react/Event.h" -#include "react/Observer.h" -#include "react/Algorithm.h" - -/////////////////////////////////////////////////////////////////////////////////////////////////// -namespace { - -using namespace react; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// SignalTest fixture -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -class TransactionTest : public testing::Test -{ -public: - template - class MyEngine : public TParams::template EngineT {}; - - REACTIVE_DOMAIN(MyDomain, TParams::mode, MyEngine) -}; - -TYPED_TEST_CASE_P(TransactionTest); - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Concurrent transactions test 1 -/////////////////////////////////////////////////////////////////////////////////////////////////// -TYPED_TEST_P(TransactionTest, Concurrent1) -{ - using D = typename Concurrent1::MyDomain; - - std::vector results; - - auto n1 = MakeVar(1); - auto n2 = n1 + 1; - auto n3 = n2 + n1 + 1; - auto n4 = n3 + 1; - auto n5 = n4 + n3 + n1 + 1; - auto n6 = n5 + 1; - auto n7 = n6 + n5 + 1; - auto n8 = n7 + 1; - auto n9 = n8 + n7 + n5 + n1 + 1; - auto n10 = n9 + 1; - auto n11 = n10 + n9 + 1; - auto n12 = n11 + 1; - auto n13 = n12 + n11 + n9 + 1; - auto n14 = n13 + 1; - auto n15 = n14 + n13 + 1; - auto n16 = n15 + 1; - auto n17 = n16 + n15 + n13 + n9 + 1; - - Observe(n17, [&] (int v) - { - results.push_back(v); - }); - - n1 <<= 10; // 7732 - n1 <<= 100; // 68572 - n1 <<= 1000; // 676972 - - ASSERT_EQ(results.size(), 3); - - ASSERT_TRUE(std::find(results.begin(), results.end(), 7732) != results.end()); - ASSERT_TRUE(std::find(results.begin(), results.end(), 68572) != results.end()); - ASSERT_TRUE(std::find(results.begin(), results.end(), 676972) != results.end()); - - // Reset - n1 <<= 1; - results.clear(); - - // Now do the same from 3 threads - - std::thread t1([&] { n1 <<= 10; }); - std::thread t2([&] { n1 <<= 100; }); - std::thread t3([&] { n1 <<= 1000; }); - - t1.join(); - t2.join(); - t3.join(); - - ASSERT_EQ(results.size(), 3); - - ASSERT_TRUE(std::find(results.begin(), results.end(), 7732) != results.end()); - ASSERT_TRUE(std::find(results.begin(), results.end(), 68572) != results.end()); - ASSERT_TRUE(std::find(results.begin(), results.end(), 676972) != results.end()); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Concurrent transactions test 2 -/////////////////////////////////////////////////////////////////////////////////////////////////// -TYPED_TEST_P(TransactionTest, Concurrent2) -{ - using D = typename Concurrent2::MyDomain; - - std::vector results; - - auto in = MakeVar(-1); - - // 1. Generate graph - Signal n0 = in; - - auto next = n0; - - for (int i=0; i < 100; i++) - { - auto q = next + 0; - next = q; - } - - Observe(next, [&] (int v) - { - results.push_back(v); - }); - - // 2. Send events - std::thread t1([&] - { - for (int i=0; i<100; i++) - { - std::this_thread::sleep_for(std::chrono::milliseconds(rand() % 50)); - in <<= i; - } - }); - - std::thread t2([&] - { - for (int i=100; i<200; i++) - { - std::this_thread::sleep_for(std::chrono::milliseconds(rand() % 50)); - in <<= i; - } - }); - - std::thread t3([&] - { - for (int i=200; i<300; i++) - { - std::this_thread::sleep_for(std::chrono::milliseconds(rand() % 50)); - in <<= i; - } - }); - - t1.join(); - t2.join(); - t3.join(); - - ASSERT_EQ(results.size(), 300); - - for (int i=0; i<300; i++) - { - ASSERT_TRUE(std::find(results.begin(), results.end(), i) != results.end()); - } -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Concurrent transactions test 3 -/////////////////////////////////////////////////////////////////////////////////////////////////// -TYPED_TEST_P(TransactionTest, Concurrent3) -{ - using D = typename Concurrent3::MyDomain; - - std::vector results; - - std::function f_0 = [] (int a) -> int - { - for (int i = 0; i<(a+1)*100; i++); - return a + 1; - }; - - std::function f_n = [] (int a, int b) -> int - { - for (int i = 0; i<(a+b)*100; i++); - return a + b; - }; - - auto n1 = MakeVar(1); - auto n2 = n1 ->* f_0; - auto n3 = ((n2, n1) ->* f_n) ->* f_0; - auto n4 = n3 ->* f_0; - auto n5 = ((((n4, n3) ->* f_n), n1) ->* f_n) ->* f_0; - auto n6 = n5 ->* f_0; - auto n7 = ((n6, n5) ->* f_n) ->* f_0; - auto n8 = n7 ->* f_0; - auto n9 = ((((((n8, n7) ->* f_n), n5) ->* f_n), n1) ->* f_n) ->* f_0; - auto n10 = n9 ->* f_0; - auto n11 = ((n10, n9) ->* f_n) ->* f_0; - auto n12 = n11 ->* f_0; - auto n13 = ((((n12, n11) ->* f_n), n9) ->* f_n) ->* f_0; - auto n14 = n13 ->* f_0; - auto n15 = ((n14, n13) ->* f_n) ->* f_0; - auto n16 = n15 ->* f_0; - auto n17 = ((((((n16, n15) ->* f_n), n13) ->* f_n), n9) ->* f_n) ->* f_0; - - Observe(n17, [&] (int v) - { - results.push_back(v); - }); - - n1 <<= 1000; // 676972 - n1 <<= 100; // 68572 - n1 <<= 10; // 7732 - - - ASSERT_EQ(results.size(), 3); - - ASSERT_TRUE(std::find(results.begin(), results.end(), 7732) != results.end()); - ASSERT_TRUE(std::find(results.begin(), results.end(), 68572) != results.end()); - ASSERT_TRUE(std::find(results.begin(), results.end(), 676972) != results.end()); - - // Reset - n1 <<= 1; - results.clear(); - - std::thread t3([&] { n1 <<= 1000; }); - std::thread t2([&] { n1 <<= 100; }); - std::thread t1([&] { n1 <<= 10; }); - - t3.join(); - t2.join(); - t1.join(); - - - ASSERT_EQ(results.size(), 3); - - ASSERT_TRUE(std::find(results.begin(), results.end(), 7732) != results.end()); - ASSERT_TRUE(std::find(results.begin(), results.end(), 68572) != results.end()); - ASSERT_TRUE(std::find(results.begin(), results.end(), 676972) != results.end()); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Merging1 -/////////////////////////////////////////////////////////////////////////////////////////////////// -TYPED_TEST_P(TransactionTest, Merging1) -{ - using D = typename Merging1::MyDomain; - - std::vector results; - - std::atomic shouldSpin(false); - - std::function f = [&shouldSpin] (int a) -> int - { - while (shouldSpin); - - return a; - }; - - auto n1 = MakeVar(1); - auto n2 = n1 ->* f; - - Observe(n2, [&] (int v) { - results.push_back(v); - }); - - // Todo: improve this as it'll fail occasionally - shouldSpin = true; - std::thread t1([&] { - DoTransaction(allow_merging, [&] { - n1 <<= 2; - }); - }); - std::this_thread::sleep_for(std::chrono::milliseconds(2000)); - std::thread t2([&] { - DoTransaction(allow_merging, [&] { - n1 <<= 3; - }); - }); - std::this_thread::sleep_for(std::chrono::milliseconds(1000)); - std::thread t3([&] { - DoTransaction(allow_merging, [&] { - n1 <<= 4; - }); - }); - std::this_thread::sleep_for(std::chrono::milliseconds(1000)); - std::thread t4([&] { - DoTransaction(allow_merging, [&] { - n1 <<= 5; - }); - - }); - std::this_thread::sleep_for(std::chrono::milliseconds(1000)); - shouldSpin = false; - - t1.join(); - t2.join(); - t3.join(); - t4.join(); - - ASSERT_EQ(results.size(), 2); - ASSERT_TRUE(results[0] == 2); - ASSERT_TRUE(results[1] == 5); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Async1 -/////////////////////////////////////////////////////////////////////////////////////////////////// -TYPED_TEST_P(TransactionTest, Async1) -{ - using D = typename Async1::MyDomain; - - std::vector results; - - auto in = MakeVar(1); - auto s1 = in * 1000; - - Observe(s1, [&] (int v) { - results.push_back(v); - }); - - TransactionStatus st; - - AsyncTransaction(st, [&] { - in <<= 10; - }); - - AsyncTransaction(st, [&] { - in <<= 20; - }); - - AsyncTransaction(st, [&] { - in <<= 30; - }); - - st.Wait(); - - ASSERT_EQ(results.size(), 3); - ASSERT_TRUE(results[0] == 10000); - ASSERT_TRUE(results[1] == 20000); - ASSERT_TRUE(results[2] == 30000); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// AsyncMerging1 -/////////////////////////////////////////////////////////////////////////////////////////////////// -TYPED_TEST_P(TransactionTest, AsyncMerging1) -{ - using D = typename AsyncMerging1::MyDomain; - - std::vector results; - - auto in = MakeVar(1); - auto s1 = in * 1000; - - Observe(s1, [&] (int v) { - results.push_back(v); - }); - - TransactionStatus st; - - AsyncTransaction(allow_merging, st, [&] { - std::this_thread::sleep_for(std::chrono::milliseconds(1000)); - in <<= 10; - }); - - // Make sure other async transaction gets to start - std::this_thread::sleep_for(std::chrono::milliseconds(10)); - - // These two can still be pulled in after the first input function is done - AsyncTransaction(allow_merging, st, [&] { - in <<= 20; - }); - - AsyncTransaction(allow_merging, st, [&] { - in <<= 30; - }); - - // Can't be merged - AsyncTransaction(st, [&] { - in <<= 40; - }); - - // These two should be merged again - AsyncTransaction(allow_merging, st, [&] { - in <<= 50; - }); - - AsyncTransaction(allow_merging, st, [&] { - in <<= 60; - }); - - st.Wait(); - - ASSERT_EQ(results.size(), 3); - ASSERT_TRUE(results[0] == 30000); - ASSERT_TRUE(results[1] == 40000); - ASSERT_TRUE(results[2] == 60000); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Continuation1 -/////////////////////////////////////////////////////////////////////////////////////////////////// -TYPED_TEST_P(TransactionTest, Continuation1) -{ - using D = typename Continuation1::MyDomain; - - std::vector results; - - auto in = MakeVar(0); - - auto cont = MakeContinuation(in, [&] (int v) { - results.push_back(v); - - if (v < 10) - in <<= v + 1; - }); - - in <<= 1; - - ASSERT_EQ(results.size(), 10); - for (int i=0; i<10; i++) - ASSERT_TRUE(results[i] == i+1); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Continuation2 -/////////////////////////////////////////////////////////////////////////////////////////////////// -TYPED_TEST_P(TransactionTest, Continuation2) -{ - using L = typename Continuation2::MyDomain; - - REACTIVE_DOMAIN(R, sequential_concurrent) - - std::vector results; - - auto srcL = MakeVar(0); - auto srcR = MakeVar(0); - - auto contL = MakeContinuation(srcL, [&] (int v) { - results.push_back(v); - if (v < 10) - srcR <<= v+1; - }); - - auto contR = MakeContinuation(Monitor(srcR), [&] (int v) { - results.push_back(v); - if (v < 10) - srcL <<= v+1; - }); - - srcL <<= 1; - - ASSERT_EQ(results.size(), 10); - for (int i=0; i<10; i++) - ASSERT_TRUE(results[i] == i+1); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Continuation3 -/////////////////////////////////////////////////////////////////////////////////////////////////// -TYPED_TEST_P(TransactionTest, Continuation3) -{ - using L = typename Continuation3::MyDomain; - - REACTIVE_DOMAIN(R, sequential_concurrent) - - std::vector results; - - auto srcL = MakeVar(0); - auto depL1 = MakeVar(100); - auto depL2 = MakeVar(10); - auto srcR = MakeVar(0); - - auto contL = MakeContinuation( - Monitor(srcL), - With(depL1, depL2), - [&] (int v, int depL1, int depL2) { - ASSERT_EQ(depL1, v*100); - ASSERT_EQ(depL2, v*10); - results.push_back(v); - if (v < 10) - srcR <<= v+1; - }); - - auto contR = MakeContinuation( - Monitor(srcR), - [&] (int v) { - results.push_back(v); - - v++; - depL1 <<= v*100; - depL2 <<= v*10; - if (v < 10) - srcL <<= v; - }); - - srcL <<= 1; - - ASSERT_EQ(results.size(), 10); - for (int i=0; i<10; i++) - ASSERT_TRUE(results[i] == i+1); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Continuation4 test -/////////////////////////////////////////////////////////////////////////////////////////////////// -TYPED_TEST_P(TransactionTest, Continuation4) -{ - using D = typename Continuation4::MyDomain; - - using std::vector; - - auto vect = MakeVar(vector{}); - - int count = 0; - - auto cont = MakeContinuation(vect, [&] (const vector& v) - { - if (count == 0) - { - ASSERT_EQ(v[0], 30); - - vect.Modify([] (vector& v) { - v.push_back(50); - }); - } - else if (count == 1) - { - ASSERT_EQ(v[1], 50); - - vect.Modify([] (vector& v) { - v.push_back(70); - }); - } - else - { - ASSERT_EQ(v[2], 70); - } - - count++; - }); - - vect.Modify([] (vector& v) { - v.push_back(30); - }); - - ASSERT_EQ(count, 3); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -REGISTER_TYPED_TEST_CASE_P -( - TransactionTest, - Concurrent1, - Concurrent2, - Concurrent3, - Merging1, - Async1, - AsyncMerging1, - Continuation1, - Continuation2, - Continuation3, - Continuation4 -); - -} // ~namespace diff --git a/tests/src/algorithm_tests.cpp b/tests/src/algorithm_tests.cpp index 6054092a..49bd221c 100644 --- a/tests/src/algorithm_tests.cpp +++ b/tests/src/algorithm_tests.cpp @@ -4,9 +4,713 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) +#include "gtest/gtest.h" + +#include "react/algorithm.h" +#include "react/observer.h" + +#include +#include +#include +#include +#include +#include + +using namespace react; + +TEST(AlgorithmTest, Hold) +{ + // Hold last value of event source in state. + + Group g; + + EventSource evt1( g ); + + State st = Hold(1, evt1); + + int output = 0; + int turns = 0; + + Observer obs([&] (int v) + { + ++turns; + output = v; + }, st); + + // Initial call. Output should take the value of initial value. + EXPECT_EQ(1, output); + EXPECT_EQ(1, turns); + + // Event changes value. + evt1.Emit(10); + + EXPECT_EQ(10, output); + EXPECT_EQ(2, turns); + + // New event, but same value, observer should not be called. + evt1.Emit(10); + + EXPECT_EQ(10, output); + EXPECT_EQ(2, turns); +} + +TEST(AlgorithmTest, Monitor1) +{ + // Emit events when value of state changes. + + Group g; + + StateVar st( g, 1 ); + + Event evt = Monitor( st ); + + int output = 0; + int turns = 0; + + Observer obs([&] (const auto& events) + { + ++turns; + + for (int e : events) + output += e; + }, evt); + + EXPECT_EQ(0, output); + EXPECT_EQ(0, turns); + + // Change from 1 -> 10: Event. + st.Set(10); + + // Change from 10 -> 20: Event. + st.Set(20); + + // Change from 20 -> 20: No event. + st.Set(20); + + // 10 + 20 were the changes. + EXPECT_EQ(30, output); + EXPECT_EQ(2, turns); +} + +TEST(AlgorithmTest, Monitor2) +{ + // Monitor state changes and filter the resulting events. + + Group g; + + StateVar target( g, 10 ); + + std::vector results; + + auto filterFunc = [] (int v) { return v > 10; }; + + { + // Observer is created in a nested scope so it gets destructed before the end of this function. + + Observer obs([&] (const auto& events) + { + for (int e : events) + results.push_back(e); + }, Filter(filterFunc, Monitor(target))); + + // Change the value a couple of times. + target.Set(10); // Change, but <= 10 + target.Set(20); // Change + target.Set(20); // No change + target.Set(10); // Change, but <= 10 + + // Only 1 non-filtered change should go through. + EXPECT_EQ(results.size(), 1); + EXPECT_EQ(results[0], 20); + } + + target.Set(100); // Change, >100, but observer is gone. + + // No changes to results without the observer. + ASSERT_EQ(results.size(), 1); +} + +TEST(AlgorithmTest, Snapshot) +{ + Group g; + + StateVar sv( g, 1 ); + EventSource<> es( g ); + + State st = Snapshot( sv, es ); + + int output = 0; + int turns = 0; + + Observer obs([&] (int v) + { + ++turns; + output = v; + }, st); + + EXPECT_EQ(1, output); + EXPECT_EQ(1, turns); + + sv.Set(10); + + EXPECT_EQ(1, output); + EXPECT_EQ(1, turns); + + es.Emit(); + + EXPECT_EQ(10, output); + EXPECT_EQ(2, turns); +} + +TEST(AlgorithmTest, Pulse) +{ + Group g; + + StateVar sv( g, 1 ); + EventSource<> es( g ); + + Event st = Pulse( sv, es ); + + int output = 0; + int turns = 0; + + Observer obs([&] (const auto& events) + { + for (int e : events) + { + ++turns; + output += e; + } + }, st); + + EXPECT_EQ(0, output); + EXPECT_EQ(0, turns); + + sv.Set(10); + + EXPECT_EQ(0, output); + EXPECT_EQ(0, turns); + + es.Emit(); + + EXPECT_EQ(10, output); + EXPECT_EQ(1, turns); +} + +TEST(AlgorithmTest, Iterate1) +{ + Group g; + + EventSource numSrc( g ); + + State numFold = Iterate(0, [] (const auto& events, int v) + { + for (int e : events) + v += e; + return v; + }, numSrc); + + for (int i=1; i<=100; ++i) + numSrc << i; + + int output = 0; + Observer obs([&] (int v) { output = v; }, numFold); + + EXPECT_EQ(output, 5050); +} + +TEST(AlgorithmTest, Iterate2) +{ + Group g; + + EventSource charSrc( g ); + + State strFold = Iterate(std::string(""), [] (const auto& events, std::string s) + { + for (char c : events) + s += c; + return s; + }, charSrc); + + std::string output; + Observer obs([&] (const auto& v) { output = v; }, strFold); + + charSrc << 'T' << 'e' << 's' << 't'; + + EXPECT_EQ(output, "Test"); +} + +TEST(AlgorithmTest, Iterate3) +{ + Group g; + + EventSource numSrc( g ); + + State numFold = Iterate(0, [] (const auto& events, int v) + { + for (int e : events) + v += e; + return v; + }, numSrc); + + int turns = 0; + int output = 0; + + Observer obs([&] (const auto& v) + { + ++turns; + output = v; + }, numFold); + + g.DoTransaction([&] + { + for (int i=1; i<=100; i++) + numSrc << i; + }); + + EXPECT_EQ(turns, 2); + EXPECT_EQ(output, 5050); +} + +template +struct Incrementer +{ + T operator()(const EventValueList& events, T v) const + { + for (auto e : events) + ++v; + return v; + } +}; + +template +struct Decrementer +{ + T operator()(const EventValueList& events, T v) const + { + for (auto e : events) + --v; + return v; + } +}; + +TEST(AlgorithmTest, Iterate4) +{ + Group g; + + EventSource<> trigger( g ); + + { + State inc = Iterate(0, Incrementer{ }, trigger); + for (int i=1; i<=100; i++) + trigger.Emit(); + + int output = 0; + Observer obs([&] (int v) { output = v; }, inc); + + EXPECT_EQ(output, 100); + } + + { + State dec = Iterate(200, Decrementer{ }, trigger); + for (int i=1; i<=100; i++) + trigger.Emit(); + + int output = 0; + Observer obs([&] (int v) { output = v; }, dec); + + ASSERT_EQ(output, 100); + } +} + +TEST(AlgorithmTest, IterateByRef1) +{ + Group g; + + EventSource src( g ); + + auto x = IterateByRef>(std::vector{ }, [] (const auto& events, auto& v) + { + for (int e : events) + v.push_back(e); + }, src); + + std::vector output; + Observer obs([&] (const auto& v) { output = v; }, x); + + // Push + for (int i=1; i<=100; i++) + src << i; + + EXPECT_EQ(output.size(), 100); + + // Check + for (int i=1; i<=100; i++) + EXPECT_EQ(output[i-1], i); +} + +TEST(AlgorithmTest, IterateByRef2) +{ + Group g; + + EventSource<> src( g ); + + auto x = IterateByRef>(std::vector{ }, [] (const auto& events, std::vector& v) + { + for (Token e : events) + v.push_back(123); + }, src); + + std::vector output; + Observer obs([&] (const auto& v) { output = v; }, x); + + // Push + for (auto i=0; i<100; i++) + src.Emit(); + + EXPECT_EQ(output.size(), 100); + + // Check + for (auto i=0; i<100; i++) + EXPECT_EQ(output[i], 123); +} -/////////////////////////////////////////////////////////////////////////////////////////////////// namespace { +template +T Sum(T a, T b) { return a + b; } + +template +T Prod(T a, T b) { return a * b; } + +template +T Diff(T a, T b) { return a - b; } + +} //~namespace + +TEST(AlgorithmTest, TransformWithState) +{ + Group g; + + StateVar in1( g ); + StateVar in2( g ); + + State sum( Sum, in1, in2 ); + State prod( Prod, in1, in2 ); + State diff( Diff, in1, in2 ); + + EventSource<> src1( g ); + EventSource src2( g ); + + auto out1 = Transform>([] (Token, int sum, int prod, int diff) + { + return std::make_tuple(sum, prod, diff); + }, src1, sum, prod, diff); + + auto out2 = Transform>([] (int e, int sum, int prod, int diff) + { + return std::make_tuple(e, sum, prod, diff); + }, src2, sum, prod, diff); + + int turns1 = 0; + int turns2 = 0; + + { + std::tuple output1; + + Observer obs1([&] (const auto& events) + { + for (const auto& e : events) + { + ++turns1; + output1 = e; + } + }, out1); + + std::tuple output2; + + Observer obs2([&] (const auto& events) + { + for (const auto& e : events) + { + ++turns2; + output2 = e; + } + }, out2); + + in1.Set(22); + in2.Set(11); + + src1.Emit(); + src2.Emit(42); + + EXPECT_EQ(std::get<0>(output1), 33); + EXPECT_EQ(std::get<1>(output1), 242); + EXPECT_EQ(std::get<2>(output1), 11); + + EXPECT_EQ(std::get<0>(output2), 42); + EXPECT_EQ(std::get<1>(output2), 33); + EXPECT_EQ(std::get<2>(output2), 242); + EXPECT_EQ(std::get<3>(output2), 11); + + EXPECT_EQ(turns1, 1); + EXPECT_EQ(turns2, 1); + } + + { + std::tuple output1; + + Observer obs1([&] (const auto& events) + { + for (const auto& e : events) + { + ++turns1; + output1 = e; + } + }, out1); + + std::tuple output2; + + Observer obs2([&] (const auto& events) + { + for (const auto& e : events) + { + ++turns2; + output2 = e; + } + }, out2); + + in1.Set(220); + in2.Set(110); + + src1.Emit(); + src2.Emit(420); + + EXPECT_EQ(std::get<0>(output1), 330); + EXPECT_EQ(std::get<1>(output1), 24200); + EXPECT_EQ(std::get<2>(output1), 110); + + EXPECT_EQ(std::get<0>(output2), 420); + EXPECT_EQ(std::get<1>(output2), 330); + EXPECT_EQ(std::get<2>(output2), 24200); + EXPECT_EQ(std::get<3>(output2), 110); + + EXPECT_EQ(turns1, 2); + EXPECT_EQ(turns2, 2); + } +} + +TEST(AlgorithmTest, IterateWithState) +{ + Group g; + + StateVar in1( g ); + StateVar in2( g ); + + State op1(Sum, in1, in2); + State op2([] (int a, int b) { return (a + b) * 10; }, in1, in2); + + EventSource<> src1( g ); + EventSource src2( g ); + + auto out1 = Iterate>(std::make_tuple(0, 0), [] (const auto& events, std::tuple t, int op1, int op2) + { + for (const auto& e : events) + t = std::make_tuple(std::get<0>(t) + op1, std::get<1>(t) + op2); + + return t; + + }, src1, op1, op2); + + auto out2 = Iterate>(std::make_tuple(0, 0, 0), [] (const auto& events, std::tuple t, int op1, int op2) + { + for (const auto& e : events) + t = std::make_tuple(std::get<0>(t) + e, std::get<1>(t) + op1, std::get<2>(t) + op2); + + return t; + }, src2, op1, op2); + + int turns1 = 0; + int turns2 = 0; + + { + std::tuple output1; + + Observer obs1([&] (const auto& v) + { + ++turns1; + output1 = v; + }, out1); + + std::tuple output2; + + Observer obs2([&] (const auto& v) + { + ++turns2; + output2 = v; + }, out2); + + in1.Set(22); + in2.Set(11); + + src1.Emit(); + src2.Emit(42); + + EXPECT_EQ(std::get<0>(output1), 33); + EXPECT_EQ(std::get<1>(output1), 330); + + EXPECT_EQ(std::get<0>(output2), 42); + EXPECT_EQ(std::get<1>(output2), 33); + EXPECT_EQ(std::get<2>(output2), 330); + + EXPECT_EQ(turns1, 2); + EXPECT_EQ(turns2, 2); + } + + { + std::tuple output1; + + Observer obs1([&] (const auto& v) + { + ++turns1; + output1 = v; + }, out1); + + std::tuple output2; + + Observer obs2([&] (const auto& v) + { + ++turns2; + output2 = v; + }, out2); + + in1.Set(220); + in2.Set(110); + + src1.Emit(); + src2.Emit(420); + + EXPECT_EQ(std::get<0>(output1), 33 + 330); + EXPECT_EQ(std::get<1>(output1), 330 + 3300); + + EXPECT_EQ(std::get<0>(output2), 42 + 420); + EXPECT_EQ(std::get<1>(output2), 33 + 330); + EXPECT_EQ(std::get<2>(output2), 330 + 3300); + + EXPECT_EQ(turns1, 4); + EXPECT_EQ(turns2, 4); + } +} + +TEST(AlgorithmTest, IterateByRefWithState) +{ + Group g; + + StateVar in1( g ); + StateVar in2( g ); + + State op1( Sum, in1, in2 ); + State op2([] (int a, int b) { return (a + b) * 10; }, in1, in2); + + EventSource<> src1( g ); + EventSource src2( g ); + + auto out1 = IterateByRef>(std::vector{ }, [] (const auto& events, std::vector& v, int op1, int op2) + { + for (const auto& e : events) + { + v.push_back(op1); + v.push_back(op2); + } + }, src1, op1, op2); + + auto out2 = IterateByRef>(std::vector{ }, [] (const auto& events, std::vector& v, int op1, int op2) + { + for (const auto& e : events) + { + v.push_back(e); + v.push_back(op1); + v.push_back(op2); + } + }, src2, op1, op2); + + int turns1 = 0; + int turns2 = 0; + + { + std::vector output1; + + Observer obs1([&] (const std::vector& v) + { + ++turns1; + output1 = v; + }, out1); + + std::vector output2; + + Observer obs2([&] (const std::vector& v) + { + ++turns2; + output2 = v; + }, out2); + + in1.Set(22); + in2.Set(11); + + src1.Emit(); + src2.Emit(42); + + EXPECT_EQ(output1.size(), 2); + EXPECT_EQ(output1[0], 33); + EXPECT_EQ(output1[1], 330); + + EXPECT_EQ(output2.size(), 3); + EXPECT_EQ(output2[0], 42); + EXPECT_EQ(output2[1], 33); + EXPECT_EQ(output2[2], 330); + + EXPECT_EQ(turns1, 2); + EXPECT_EQ(turns2, 2); + } + + { + std::vector output1; + + Observer obs1([&] (const std::vector& v) + { + ++turns1; + output1 = v; + }, out1); + + std::vector output2; + + Observer obs2([&] (const std::vector& v) + { + ++turns2; + output2 = v; + }, out2); + + in1.Set(220); + in2.Set(110); + + src1.Emit(); + src2.Emit(420); + + EXPECT_EQ(output1.size(), 4); + EXPECT_EQ(output1[0], 33); + EXPECT_EQ(output1[1], 330); + EXPECT_EQ(output1[2], 330); + EXPECT_EQ(output1[3], 3300); + + EXPECT_EQ(output2.size(), 6); + EXPECT_EQ(output2[0], 42); + EXPECT_EQ(output2[1], 33); + EXPECT_EQ(output2[2], 330); + EXPECT_EQ(output2[3], 420); + EXPECT_EQ(output2[4], 330); + EXPECT_EQ(output2[5], 3300); -} // ~namespace \ No newline at end of file + EXPECT_EQ(turns1, 4); + EXPECT_EQ(turns2, 4); + } +} diff --git a/tests/src/event_tests.cpp b/tests/src/event_tests.cpp index 98d27bfc..168ac619 100644 --- a/tests/src/event_tests.cpp +++ b/tests/src/event_tests.cpp @@ -7,6 +7,7 @@ #include "gtest/gtest.h" #include "react/event.h" +#include "react/state.h" #include "react/observer.h" #include @@ -168,10 +169,7 @@ TEST(EventTest, Transactions) g.DoTransaction([&] { - evt.Emit(1); - evt.Emit(1); - evt.Emit(1); - evt.Emit(1); + evt << 1 << 1 << 1 << 1; }); EXPECT_EQ(4, output); @@ -212,9 +210,9 @@ TEST(EventTest, Links) output += e; }, slot); - evt1.Emit(1); - evt2.Emit(1); - evt3.Emit(1); + evt1 << 1; + evt2 << 1; + evt3 << 1; std::this_thread::sleep_for(std::chrono::seconds(1)); @@ -244,13 +242,8 @@ TEST(EventTest, EventSources) results2.push(e); }, es2); - es1.Emit(10); - es1.Emit(20); - es1.Emit(30); - - es2.Emit(40); - es2.Emit(50); - es2.Emit(60); + es1 << 10 << 20 << 30; + es2 << 40 << 50 << 60; // First batch. EXPECT_FALSE(results1.empty()); @@ -453,7 +446,7 @@ TEST(EventTest, Transform) EXPECT_TRUE(std::find(results.begin(), results.end(), "HELLO VORLD") != results.end()); } -TEST(EventTest, Chain) +TEST(EventTest, Flow) { Group g; @@ -537,4 +530,130 @@ TEST(EventTest, Join) in1.Emit(20); EXPECT_EQ(results.size(), 2); EXPECT_EQ(results[1], std::make_tuple(20, 20, 20)); +} + +TEST(EventTest, FilterWithState) +{ + Group g; + + EventSource in( g ); + + StateVar sig1( g, 1338 ); + StateVar sig2( g, 1336 ); + + EventSource in2( g ); + + auto filtered = Filter([] (const std::string& s, int sig1, int sig2) + { + return s == "Hello World" && sig1 > sig2; + }, in, sig1, sig2); + + std::queue results; + + Observer obs([&] (const auto& events) + { + for (const auto& e : events) + results.push(e); + }, filtered); + + in << std::string("Hello Worlt") << std::string("Hello World") << std::string("Hello Vorld"); + sig1.Set(1335); + in << std::string("Hello Vorld"); + + EXPECT_FALSE(results.empty()); + EXPECT_EQ(results.front(), "Hello World"); + results.pop(); + + EXPECT_TRUE(results.empty()); +} + +TEST(EventTest, TransformWithState) +{ + Group g; + + std::vector results; + + EventSource in1( g ); + EventSource in2( g ); + + Event merged = Merge(in1, in2); + + StateVar first( g, "Ace" ); + StateVar last( g, "McSteele" ); + + auto transformed = Transform([] (std::string s, const std::string& first, const std::string& last) -> std::string + { + std::transform(s.begin(), s.end(), s.begin(), ::toupper); + s += std::string(", ") + first + std::string(" ") + last; + return s; + }, merged, first, last); + + Observer obs([&] (const auto& events) + { + for (const auto& e : events) + results.push_back(e); + }, transformed); + + in1 << std::string("Hello Worlt") << std::string("Hello World"); + + g.DoTransaction([&] + { + in2 << std::string("Hello Vorld"); + first.Set(std::string("Alice")); + last.Set(std::string("Anderson")); + }); + + EXPECT_EQ(results.size(), 3); + EXPECT_TRUE(std::find(results.begin(), results.end(), "HELLO WORLT, Ace McSteele") != results.end()); + EXPECT_TRUE(std::find(results.begin(), results.end(), "HELLO WORLD, Ace McSteele") != results.end()); + EXPECT_TRUE(std::find(results.begin(), results.end(), "HELLO VORLD, Alice Anderson") != results.end()); +} + +TEST(EventTest, FlowWithState) +{ + Group g; + + std::vector results; + + EventSource in1( g ); + EventSource in2( g ); + + StateVar mult( g, 10 ); + + Event merged = Merge(in1, in2); + int callCount = 0; + + Event processed([&] (const auto& events, auto out, int mult) + { + for (const auto& e : events) + { + *out = 0.1f * e * mult; + *out = 1.5f * e * mult; + } + + callCount++; + }, merged, mult); + + Observer obs([&] (const auto& events) + { + for (float e : events) + results.push_back(e); + }, processed); + + g.DoTransaction([&] + { + in1 << 10 << 20; + }); + + in2 << 30; + + EXPECT_EQ(results.size(), 6); + EXPECT_EQ(callCount, 2); + + EXPECT_EQ(results[0], 10.0f); + EXPECT_EQ(results[1], 150.0f); + EXPECT_EQ(results[2], 20.0f); + EXPECT_EQ(results[3], 300.0f); + EXPECT_EQ(results[4], 30.0f); + EXPECT_EQ(results[5], 450.0f); } \ No newline at end of file diff --git a/tests/src/state_tests.cpp b/tests/src/state_tests.cpp index 7cca28db..953cedc8 100644 --- a/tests/src/state_tests.cpp +++ b/tests/src/state_tests.cpp @@ -202,6 +202,9 @@ TEST(StateTest, Links) std::this_thread::sleep_for(std::chrono::seconds(1)); } +namespace +{ + template static T Sum2(T a, T b) { @@ -214,7 +217,9 @@ static T Sum3(T a, T b, T c) return a + b + c; } -TEST(StateTest, StateCombination) +} // ~namespace + +TEST(StateTest, StateCombination1) { Group g; @@ -259,4 +264,164 @@ TEST(StateTest, StateCombination) EXPECT_EQ(3, output2); EXPECT_EQ(4, turns2); +} + +TEST(StateTest, StateCombination2) +{ + Group g; + + std::vector results; + + StateVar n1( g, 1 ); + + State n2([] (int n1) + { return n1 + 1; }, n1); + + State n3([] (int n1, int n2) + { return n2 + n1 + 1; }, n1, n2); + + State n4([] (int n3) + { return n3 + 1; }, n3); + + State n5([] (int n1, int n3, int n4) + { return n4 + n3 + n1 + 1; }, n1, n3, n4); + + State n6([] (int n5) + { return n5 + 1; }, n5); + + State n7([] (int n5, int n6) + { return n6 + n5 + 1; }, n5, n6); + + State n8([] (int n7) + { return n7 + 1; }, n7); + + State n9([] (int n1, int n5, int n7, int n8) + { return n8 + n7 + n5 + n1 + 1; }, n1, n5, n7, n8); + + State n10([] (int n9) + { return n9 + 1; }, n9); + + State n11([] (int n9, int n10) + { return n10 + n9 + 1; }, n9, n10); + + State n12([] (int n11) + { return n11 + 1; }, n11); + + State n13([] (int n9, int n11, int n12) + { return n12 + n11 + n9 + 1; }, n9, n11, n12); + + State n14([] (int n13) + { return n13 + 1; }, n13); + + State n15([] (int n13, int n14) + { return n14 + n13 + 1; }, n13, n14); + + State n16([] (int n15) + { return n15 + 1; }, n15); + + State n17([] (int n9, int n13, int n15, int n16) + { return n16 + n15 + n13 + n9 + 1; }, n9, n13, n15, n16); + + Observer obs([&] (int v) { results.push_back(v); }, n17); + + n1.Set(10); // 7732 + n1.Set(100); // 68572 + n1.Set(1000); // 676972 + + EXPECT_EQ(results.size(), 4); + + EXPECT_EQ(results[0], 1648); + EXPECT_EQ(results[1], 7732); + EXPECT_EQ(results[2], 68572); + EXPECT_EQ(results[3], 676972); +} + +TEST(StateTest, Modify1) +{ + Group g; + + std::vector results; + + StateVar> var( g, std::vector{ } ); + + int turns = 0; + + Observer obs([&] (const std::vector& v) + { + ++turns; + results = v; + }, var); + + var.Modify([] (std::vector& v) + { + v.push_back(30); + v.push_back(50); + v.push_back(70); + }); + + EXPECT_EQ(results[0], 30); + EXPECT_EQ(results[1], 50); + EXPECT_EQ(results[2], 70); + + EXPECT_EQ(turns, 2); +} + +TEST(StateTest, Modify2) +{ + Group g; + + std::vector results; + + StateVar> var( g, std::vector{ } ); + + int turns = 0; + + Observer obs([&] (const std::vector& v) + { + ++turns; + results = v; + }, var); + + g.DoTransaction([&] + { + var.Modify([] (std::vector& v) { v.push_back(30); }); + var.Modify([] (std::vector& v) { v.push_back(50); }); + var.Modify([] (std::vector& v) { v.push_back(70); }); + }); + + EXPECT_EQ(results[0], 30); + EXPECT_EQ(results[1], 50); + EXPECT_EQ(results[2], 70); + + EXPECT_EQ(turns, 2); +} + +TEST(StateTest, Modify3) +{ + Group g; + + std::vector results; + + StateVar> var( g, std::vector{ } ); + + int turns = 0; + + Observer obs([&] (const std::vector& v) + { + ++turns; + results = v; + }, var); + + // Also terrible + g.DoTransaction([&] + { + var.Set(std::vector{ 30, 50 }); + var.Modify([] (std::vector& v) { v.push_back(70); }); + }); + + EXPECT_EQ(results[0], 30); + EXPECT_EQ(results[1], 50); + EXPECT_EQ(results[2], 70); + + ASSERT_EQ(turns, 2); } \ No newline at end of file diff --git a/tests/src/transaction_tests.cpp b/tests/src/transaction_tests.cpp index 33812c75..01e65ac9 100644 --- a/tests/src/transaction_tests.cpp +++ b/tests/src/transaction_tests.cpp @@ -6,6 +6,7 @@ #include "gtest/gtest.h" +#include "react/state.h" #include "react/event.h" #include "react/observer.h" @@ -14,7 +15,7 @@ using namespace react; -TEST(TransactionTests, Merging) +TEST(TransactionTest, Merging) { Group g; @@ -68,7 +69,7 @@ TEST(TransactionTests, Merging) EXPECT_EQ(21, output); } -TEST(TransactionTests, LinkedSync) +TEST(TransactionTest, LinkedSync) { // Three groups. Each has one event with an observer attached. // The last observer adds a little delay. @@ -138,7 +139,7 @@ TEST(TransactionTests, LinkedSync) EXPECT_EQ(3, output3); } -TEST(TransactionTests, LinkedSyncMerging) +TEST(TransactionTest, LinkedSyncMerging) { // Two groups. Each has one event with an observer attached. // The last observer adds a little delay. From 6eb759c7e12e9647c9f41e35b35f665cc518f8a9 Mon Sep 17 00:00:00 2001 From: schlangster Date: Mon, 30 Oct 2017 02:07:57 +0100 Subject: [PATCH 58/75] Refactoring of object creation: -Ctor +static Create. Cleanup. Object state. --- CMakeLists.txt | 6 +- benchmarks/src/Main.cpp | 10 +- include/react/api.h | 23 ++++ include/react/common/syncpoint.h | 3 +- include/react/detail/event_nodes.h | 7 +- include/react/detail/state_nodes.h | 92 ++++++++++++-- include/react/event.h | 149 +++++++++++----------- include/react/observer.h | 55 ++++----- include/react/state.h | 192 ++++++++++++++++++++--------- project/msvc/CppReact.vcxproj | 1 + tests/CMakeLists.txt | 16 +-- tests/src/algorithm_tests.cpp | 112 ++++++++--------- tests/src/event_tests.cpp | 122 +++++++++--------- tests/src/state_tests.cpp | 159 ++++++++++++++++-------- tests/src/transaction_tests.cpp | 18 +-- 15 files changed, 594 insertions(+), 371 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ae21be06..3b6477a8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,11 +13,7 @@ include_directories ("${PROJECT_SOURCE_DIR}/include") ### CppReact add_library(CppReact - src/engine/PulsecountEngine.cpp - src/engine/SubtreeEngine.cpp - src/engine/ToposortEngine.cpp - src/logging/EventLog.cpp - src/logging/EventRecords.cpp) + src/detail/graph_impl.cpp) target_link_libraries(CppReact tbb) diff --git a/benchmarks/src/Main.cpp b/benchmarks/src/Main.cpp index bc42b726..a191ccbc 100644 --- a/benchmarks/src/Main.cpp +++ b/benchmarks/src/Main.cpp @@ -222,10 +222,18 @@ int main() } +struct Data +{ + State a; + State b; + + State (a, b); +}; + #endif #include "react/common/expected.h" -#include "react/signal.h" +#include "react/state.h" #include "react/event.h" #include "react/algorithm.h" #include diff --git a/include/react/api.h b/include/react/api.h index d8d15204..95ce57f6 100644 --- a/include/react/api.h +++ b/include/react/api.h @@ -9,6 +9,8 @@ #pragma once +#include + #include "react/detail/defs.h" #include "react/common/utility.h" @@ -35,6 +37,14 @@ REACT_DEFINE_BITMASK_OPERATORS(TransactionFlags) enum class Token { value }; +enum class InPlaceTag +{ + value = 1 +}; + +static constexpr InPlaceTag in_place = InPlaceTag::value; + + /////////////////////////////////////////////////////////////////////////////////////////////////// /// API types /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -55,6 +65,13 @@ class StateSlot; template class StateLink; +// Object state +template +class ObjectContext; + +template +class ObjectState; + // Event enum class Token; @@ -67,6 +84,12 @@ class EventSource; template class EventSlot; +template +using EventValueList = std::vector; + +template +using EventValueSink = std::back_insert_iterator>; + // Observer class Observer; diff --git a/include/react/common/syncpoint.h b/include/react/common/syncpoint.h index b4fc73f8..1d47952a 100644 --- a/include/react/common/syncpoint.h +++ b/include/react/common/syncpoint.h @@ -16,6 +16,7 @@ #include #include #include +#include /*****************************************/ REACT_BEGIN /*****************************************/ @@ -29,8 +30,6 @@ class SyncPoint class Dependency; private: - - class ISyncTarget { public: diff --git a/include/react/detail/event_nodes.h b/include/react/detail/event_nodes.h index 7c988b23..c918afec 100644 --- a/include/react/detail/event_nodes.h +++ b/include/react/detail/event_nodes.h @@ -27,11 +27,6 @@ /////////////////////////////////////////////////////////////////////////////////////////////////// /// Iterators for event processing /////////////////////////////////////////////////////////////////////////////////////////////////// -template -using EventValueList = std::vector; - -template -using EventValueSink = std::back_insert_iterator>; /******************************************/ REACT_END /******************************************/ @@ -493,6 +488,8 @@ template class EventInternals { public: + EventInternals() = default; + EventInternals(const EventInternals&) = default; EventInternals& operator=(const EventInternals&) = default; diff --git a/include/react/detail/state_nodes.h b/include/react/detail/state_nodes.h index c3b717b2..ea78c20b 100644 --- a/include/react/detail/state_nodes.h +++ b/include/react/detail/state_nodes.h @@ -20,12 +20,6 @@ /***************************************/ REACT_IMPL_BEGIN /**************************************/ -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Forward declarations -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -bool Equals(const L& lhs, const R& rhs); - /////////////////////////////////////////////////////////////////////////////////////////////////// /// StateNode /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -33,12 +27,6 @@ template class StateNode : public NodeBase { public: - StateNode(StateNode&&) = default; - StateNode& operator=(StateNode&&) = default; - - StateNode(const StateNode&) = delete; - StateNode& operator=(const StateNode&) = delete; - explicit StateNode(const Group& group) : StateNode::NodeBase( group ), value_( ) @@ -50,6 +38,12 @@ class StateNode : public NodeBase value_( std::forward(value) ) { } + template + StateNode(InPlaceTag, const Group& group, Ts&& ... args) : + StateNode::NodeBase( group ), + value_( std::forward(args) ... ) + { } + S& Value() { return value_; } @@ -153,7 +147,7 @@ class StateVarNode : public StateNode }; /////////////////////////////////////////////////////////////////////////////////////////////////// -/// StateOpNode +/// StateFuncNode /////////////////////////////////////////////////////////////////////////////////////////////////// template class StateFuncNode : public StateNode @@ -344,6 +338,64 @@ class StateLinkNode : public StateNode VirtualOutputNode linkOutput_; }; +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// ObjectStateNode +/////////////////////////////////////////////////////////////////////////////////////////////////// +template +class ObjectStateNode : public StateNode> +{ +public: + ObjectStateNode(const Group& group, S&& obj, const std::initializer_list& memberIds) : + ObjectStateNode::StateNode( group, std::move(obj) ) + { + this->RegisterMe(); + + if (memberIds.size() == 0) + { + apply([this] (const auto& ... members) + { + REACT_EXPAND_PACK(memberIds_.push_back(GetInternals(members).GetNodeId())); + REACT_EXPAND_PACK(this->AttachToMe(GetInternals(members).GetNodeId())); + }, this->Value().GetObject().GetReactiveMembers()); + } + else + { + memberIds_.reserve(memberIds.size()); + + for (NodeId id : memberIds) + { + memberIds_.push_back(id); + this->AttachToMe(id); + } + } + } + + template + ObjectStateNode(InPlaceTag, const Group& group, Us&& ... args) : + ObjectStateNode::StateNode( in_place, group, group, std::forward(args) ... ) + { + this->RegisterMe(); + + apply([this] (const auto& ... members) + { REACT_EXPAND_PACK(memberIds_.push_back(GetInternals(members).GetNodeId())); }, this->Value().GetObject().GetReactiveMembers()); + } + + ~ObjectStateNode() + { + for (NodeId id : memberIds_) + this->DetachFromMe(id); + + this->UnregisterMe(); + } + + virtual UpdateResult Update(TurnId turnId) noexcept override + { + return UpdateResult::changed; + } + +private: + std::vector memberIds_; +}; /////////////////////////////////////////////////////////////////////////////////////////////////// /// StateInternals @@ -352,6 +404,8 @@ template class StateInternals { public: + StateInternals() = default; + StateInternals(const StateInternals&) = default; StateInternals& operator=(const StateInternals&) = default; @@ -381,6 +435,18 @@ class StateInternals std::shared_ptr> nodePtr_; }; +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// SameGroupOrLink +/////////////////////////////////////////////////////////////////////////////////////////////////// +template +static State SameGroupOrLink(const Group& targetGroup, const State& dep) +{ + if (dep.GetGroup() == targetGroup) + return dep; + else + return StateLink::Create(targetGroup, dep); +} + /****************************************/ REACT_IMPL_END /***************************************/ #endif // REACT_DETAIL_GRAPH_STATENODES_H_INCLUDED \ No newline at end of file diff --git a/include/react/event.h b/include/react/event.h index ecde17b2..aeaaa6f6 100644 --- a/include/react/event.h +++ b/include/react/event.h @@ -31,35 +31,33 @@ template class Event : protected REACT_IMPL::EventInternals { public: - Event(const Event&) = default; - Event& operator=(const Event&) = default; - - Event(Event&&) = default; - Event& operator=(Event&&) = default; - // Construct with explicit group template - Event(const Group& group, F&& func, const Event& dep) : - Event::Event( CreateProcessingNode(group, std::forward(func), dep) ) - { } + static Event Create(const Group& group, F&& func, const Event& dep) + { return CreateProcessingNode(group, std::forward(func), dep); } // Construct with implicit group template - Event(F&& func, const Event& dep) : - Event::Event( CreateProcessingNode(dep.GetGroup(), std::forward(func), dep) ) - { } + static Event Create(F&& func, const Event& dep) + { return CreateProcessingNode(dep.GetGroup(), std::forward(func), dep); } // Construct with explicit group template - Event(const Group& group, F&& func, const Event& dep, const State& ... states) : - Event::Event( CreateSyncedProcessingNode(group, std::forward(func), dep, states ...) ) - { } + static Event Create(const Group& group, F&& func, const Event& dep, const State& ... states) + { return CreateSyncedProcessingNode(group, std::forward(func), dep, states ...); } // Construct with implicit group template - Event(F&& func, const Event& dep, const State& ... states) : - Event::Event( CreateSyncedProcessingNode(dep.GetGroup(), std::forward(func), dep, states ...) ) - { } + static Event Create(F&& func, const Event& dep, const State& ... states) + { return CreateSyncedProcessingNode(dep.GetGroup(), std::forward(func), dep, states ...); } + + Event() = default; + + Event(const Event&) = default; + Event& operator=(const Event&) = default; + + Event(Event&&) = default; + Event& operator=(Event&&) = default; auto Tokenize() const -> decltype(auto) { return REACT::Tokenize(*this); } @@ -83,13 +81,12 @@ class Event : protected REACT_IMPL::EventInternals { return e; } protected: - // Private node ctor - explicit Event(std::shared_ptr>&& nodePtr) : + Event(std::shared_ptr>&& nodePtr) : Event::EventInternals( std::move(nodePtr) ) { } template - auto CreateProcessingNode(const Group& group, F&& func, const Event& dep) -> decltype(auto) + static auto CreateProcessingNode(const Group& group, F&& func, const Event& dep) -> decltype(auto) { using REACT_IMPL::EventProcessingNode; using REACT_IMPL::SameGroupOrLink; @@ -99,7 +96,7 @@ class Event : protected REACT_IMPL::EventInternals } template - auto CreateSyncedProcessingNode(const Group& group, F&& func, const Event& dep, const State& ... syncs) -> decltype(auto) + static auto CreateSyncedProcessingNode(const Group& group, F&& func, const Event& dep, const State& ... syncs) -> decltype(auto) { using REACT_IMPL::SyncedEventProcessingNode; using REACT_IMPL::SameGroupOrLink; @@ -119,16 +116,17 @@ template class EventSource : public Event { public: + // Construct event source + static EventSource Create(const Group& group) + { return CreateSourceNode(group); } + + EventSource() = default; + EventSource(const EventSource&) = default; EventSource& operator=(const EventSource&) = default; EventSource(EventSource&& other) = default; EventSource& operator=(EventSource&& other) = default; - - // Construct event source - explicit EventSource(const Group& group) : - EventSource::Event( CreateSourceNode(group) ) - { } void Emit(const E& value) { EmitValue(value); } @@ -147,13 +145,17 @@ class EventSource : public Event { EmitValue(std::move(value)); return *this; } protected: - auto CreateSourceNode(const Group& group) -> decltype(auto) + EventSource(std::shared_ptr>&& nodePtr) : + EventSource::Event( std::move(nodePtr) ) + { } + +private: + static auto CreateSourceNode(const Group& group) -> decltype(auto) { using REACT_IMPL::EventSourceNode; return std::make_shared>(group); } -private: template void EmitValue(T&& value) { @@ -177,17 +179,18 @@ template class EventSlot : public Event { public: + // Construct emtpy slot + static EventSlot Create(const Group& group) + { return CreateSlotNode(group); } + + EventSlot() = default; + EventSlot(const EventSlot&) = default; EventSlot& operator=(const EventSlot&) = default; EventSlot(EventSlot&&) = default; EventSlot& operator=(EventSlot&&) = default; - // Construct emtpy slot - EventSlot(const Group& group) : - EventSlot::Event( CreateSlotNode(group) ) - { } - void Add(const Event& input) { AddInput(input); } @@ -198,13 +201,17 @@ class EventSlot : public Event { RemoveAllInputs(); } protected: - auto CreateSlotNode(const Group& group) -> decltype(auto) + EventSlot(std::shared_ptr>&& nodePtr) : + EventSlot::Event( std::move(nodePtr) ) + { } + +private: + static auto CreateSlotNode(const Group& group) -> decltype(auto) { using REACT_IMPL::EventSlotNode; return std::make_shared>(group); } -private: void AddInput(const Event& input) { using REACT_IMPL::NodeId; @@ -252,18 +259,24 @@ template class EventLink : public Event { public: + // Construct with group + static EventLink Create(const Group& group, const Event& input) + { return GetOrCreateLinkNode(group, input); } + + EventLink() = default; + EventLink(const EventLink&) = default; EventLink& operator=(const EventLink&) = default; EventLink(EventLink&&) = default; EventLink& operator=(EventLink&&) = default; - // Construct with group - EventLink(const Group& group, const Event& input) : - EventLink::Event( GetOrCreateLinkNode(group, input) ) +protected: + EventLink(std::shared_ptr>&& nodePtr) : + EventLink::Event( std::move(nodePtr) ) { } -protected: +private: static auto GetOrCreateLinkNode(const Group& group, const Event& input) -> decltype(auto) { using REACT_IMPL::EventLinkNode; @@ -274,9 +287,7 @@ class EventLink : public Event ReactGraph::LinkCache& linkCache = GetInternals(group).GetGraphPtr()->GetLinkCache(); - std::shared_ptr nodePtr = linkCache.LookupOrCreate( - k, - [&] + std::shared_ptr nodePtr = linkCache.LookupOrCreate(k, [&] { auto nodePtr = std::make_shared>(group, input); nodePtr->SetWeakSelfPtr(std::weak_ptr>{ nodePtr }); @@ -291,7 +302,7 @@ class EventLink : public Event /// Merge /////////////////////////////////////////////////////////////////////////////////////////////////// template -auto Merge(const Group& group, const Event& dep1, const Event& ... deps) -> Event +static auto Merge(const Group& group, const Event& dep1, const Event& ... deps) -> Event { using REACT_IMPL::EventMergeNode; using REACT_IMPL::SameGroupOrLink; @@ -302,79 +313,79 @@ auto Merge(const Group& group, const Event& dep1, const Event& ... deps) } template -auto Merge(const Event& dep1, const Event& ... deps) -> decltype(auto) +static auto Merge(const Event& dep1, const Event& ... deps) -> decltype(auto) { return Merge(dep1.GetGroup(), dep1, deps ...); } /////////////////////////////////////////////////////////////////////////////////////////////////// /// Filter /////////////////////////////////////////////////////////////////////////////////////////////////// template -auto Filter(const Group& group, F&& pred, const Event& dep) -> Event +static auto Filter(const Group& group, F&& pred, const Event& dep) -> Event { auto filterFunc = [capturedPred = std::forward(pred)] (const EventValueList& events, EventValueSink out) { std::copy_if(events.begin(), events.end(), out, capturedPred); }; - return Event(group, std::move(filterFunc), dep); + return Event::Create(group, std::move(filterFunc), dep); } template -auto Filter(F&& pred, const Event& dep) -> Event +static auto Filter(F&& pred, const Event& dep) -> Event { return Filter(dep.GetGroup(), std::forward(pred), dep); } template -auto Filter(const Group& group, F&& pred, const Event& dep, const State& ... states) -> Event +static auto Filter(const Group& group, F&& pred, const Event& dep, const State& ... states) -> Event { auto filterFunc = [capturedPred = std::forward(pred)] (const EventValueList& evts, EventValueSink out, const Ts& ... values) - { - for (const auto& v : evts) - if (capturedPred(v, values ...)) - *out++ = v; - }; + { + for (const auto& v : evts) + if (capturedPred(v, values ...)) + *out++ = v; + }; - return Event(group, std::move(filterFunc), dep, states ...); + return Event::Create(group, std::move(filterFunc), dep, states ...); } template -auto Filter(F&& pred, const Event& dep, const State& ... states) -> Event +static auto Filter(F&& pred, const Event& dep, const State& ... states) -> Event { return Filter(dep.GetGroup(), std::forward(pred), dep, states ...); } /////////////////////////////////////////////////////////////////////////////////////////////////// /// Transform /////////////////////////////////////////////////////////////////////////////////////////////////// template -auto Transform(const Group& group, F&& op, const Event& dep) -> Event +static auto Transform(const Group& group, F&& op, const Event& dep) -> Event { auto transformFunc = [capturedOp = std::forward(op)] (const EventValueList& evts, EventValueSink out) { std::transform(evts.begin(), evts.end(), out, capturedOp); }; - return Event(group, std::move(transformFunc), dep); + return Event::Create(group, std::move(transformFunc), dep); } template -auto Transform(F&& op, const Event& dep) -> Event +static auto Transform(F&& op, const Event& dep) -> Event { return Transform(dep.GetGroup(), std::forward(op), dep); } template -auto Transform(const Group& group, F&& op, const Event& dep, const State& ... states) -> Event +static auto Transform(const Group& group, F&& op, const Event& dep, const State& ... states) -> Event { auto transformFunc = [capturedOp = std::forward(op)] (const EventValueList& evts, EventValueSink out, const Us& ... values) - { - for (const auto& v : evts) - *out++ = capturedOp(v, values ...); - }; + { + for (const auto& v : evts) + *out++ = capturedOp(v, values ...); + }; - return Event(group, std::move(transformFunc), dep, states ...); + return Event::Create(group, std::move(transformFunc), dep, states ...); } template -auto Transform(F&& op, const Event& dep, const State& ... states) -> Event +static auto Transform(F&& op, const Event& dep, const State& ... states) -> Event { return Transform(dep.GetGroup(), std::forward(op), dep, states ...); } /////////////////////////////////////////////////////////////////////////////////////////////////// /// Join /////////////////////////////////////////////////////////////////////////////////////////////////// template -auto Join(const Group& group, const Event& dep1, const Event& ... deps) -> Event> +static auto Join(const Group& group, const Event& dep1, const Event& ... deps) -> Event> { using REACT_IMPL::EventJoinNode; using REACT_IMPL::SameGroupOrLink; @@ -387,7 +398,7 @@ auto Join(const Group& group, const Event& dep1, const Event& ... deps) } template -auto Join(const Event& dep1, const Event& ... deps) -> Event> +static auto Join(const Event& dep1, const Event& ... deps) -> Event> { return Join(dep1.GetGroup(), dep1, deps ...); } /******************************************/ REACT_END /******************************************/ @@ -400,7 +411,7 @@ static Event SameGroupOrLink(const Group& targetGroup, const Event& dep) if (dep.GetGroup() == targetGroup) return dep; else - return EventLink{ targetGroup, dep }; + return EventLink::Create(targetGroup, dep); } /****************************************/ REACT_IMPL_END /***************************************/ diff --git a/include/react/observer.h b/include/react/observer.h index 3f228ffd..a5360478 100644 --- a/include/react/observer.h +++ b/include/react/observer.h @@ -29,57 +29,50 @@ class Observer : protected REACT_IMPL::ObserverInternals using NodeType = REACT_IMPL::ObserverNode; public: - Observer(const Observer&) = default; - Observer& operator=(const Observer&) = default; - - Observer(Observer&&) = default; - Observer& operator=(Observer&&) = default; - // Construct state observer with explicit group template - Observer(const Group& group, F&& func, const State& subject1, const State& ... subjects) : - Observer::Observer( CreateStateObserverNode(group, std::forward(func), subject1, subjects ...)) - { } + static Observer Create(const Group& group, F&& func, const State& subject1, const State& ... subjects) + { return CreateStateObserverNode(group, std::forward(func), subject1, subjects ...); } // Construct state observer with implicit group template - Observer(F&& func, const State& subject1, const State& ... subjects) : - Observer::Observer( CreateStateObserverNode(subject1.GetGroup(), std::forward(func), subject1, subjects ...)) - { } + static Observer Create(F&& func, const State& subject1, const State& ... subjects) + { return CreateStateObserverNode(subject1.GetGroup(), std::forward(func), subject1, subjects ...); } // Construct event observer with explicit group template - Observer(const Group& group, F&& func, const Event& subject) : - Observer::Observer( CreateEventObserverNode(group, std::forward(func), subject)) - { } + static Observer Create(const Group& group, F&& func, const Event& subject) + { return CreateEventObserverNode(group, std::forward(func), subject); } // Construct event observer with implicit group template - Observer(F&& func, const Event& subject) : - Observer::Observer( CreateEventObserverNode(subject.GetGroup(), std::forward(func), subject)) - { } + static Observer Create(F&& func, const Event& subject) + { return CreateEventObserverNode(subject.GetGroup(), std::forward(func), subject); } // Constructed synced event observer with explicit group template - Observer(const Group& group, F&& func, const Event& subject, const State& ... states) : - Observer::Observer( CreateSyncedEventObserverNode(group, std::forward(func), subject, states ...)) - { } + static Observer Create(const Group& group, F&& func, const Event& subject, const State& ... states) + { return CreateSyncedEventObserverNode(group, std::forward(func), subject, states ...); } // Constructed synced event observer with implicit group template - Observer(F&& func, const Event& subject, const State& ... states) : - Observer::Observer( CreateSyncedEventObserverNode(subject.GetGroup(), std::forward(func), subject, states ...)) - { } + static Observer Create(F&& func, const Event& subject, const State& ... states) + { return CreateSyncedEventObserverNode(subject.GetGroup(), std::forward(func), subject, states ...); } + + Observer(const Observer&) = default; + Observer& operator=(const Observer&) = default; -public: //Internal - // Private node ctor - explicit Observer(std::shared_ptr&& nodePtr) : + Observer(Observer&&) = default; + Observer& operator=(Observer&&) = default; + +protected: //Internal + Observer(std::shared_ptr&& nodePtr) : nodePtr_(std::move(nodePtr)) { } -protected: +private: template - auto CreateStateObserverNode(const Group& group, F&& func, const State& dep1, const State& ... deps) -> decltype(auto) + static auto CreateStateObserverNode(const Group& group, F&& func, const State& dep1, const State& ... deps) -> decltype(auto) { using REACT_IMPL::StateObserverNode; return std::make_shared::type, T1, Ts ...>>( @@ -87,7 +80,7 @@ class Observer : protected REACT_IMPL::ObserverInternals } template - auto CreateEventObserverNode(const Group& group, F&& func, const Event& dep) -> decltype(auto) + static auto CreateEventObserverNode(const Group& group, F&& func, const Event& dep) -> decltype(auto) { using REACT_IMPL::EventObserverNode; return std::make_shared::type, T>>( @@ -95,7 +88,7 @@ class Observer : protected REACT_IMPL::ObserverInternals } template - auto CreateSyncedEventObserverNode(const Group& group, F&& func, const Event& dep, const State& ... syncs) -> decltype(auto) + static auto CreateSyncedEventObserverNode(const Group& group, F&& func, const Event& dep, const State& ... syncs) -> decltype(auto) { using REACT_IMPL::SyncedEventObserverNode; return std::make_shared::type, T, Us ...>>( diff --git a/include/react/state.h b/include/react/state.h index 95d80b6c..6c93de6c 100644 --- a/include/react/state.h +++ b/include/react/state.h @@ -13,15 +13,13 @@ #include "react/api.h" #include "react/group.h" #include "react/common/ptrcache.h" +#include "react/detail/state_nodes.h" #include #include #include #include -#include "react/detail/state_nodes.h" - - /*****************************************/ REACT_BEGIN /*****************************************/ /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -31,23 +29,23 @@ template class State : protected REACT_IMPL::StateInternals { public: - State(const State&) = default; - State& operator=(const State&) = default; - - State(State&&) = default; - State& operator=(State&&) = default; - // Construct with explicit group template - explicit State(const Group& group, F&& func, const State& dep1, const State& ... deps) : - State::StateInternals( CreateFuncNode(group, std::forward(func), dep1, deps ...) ) - { } + static State Create(const Group& group, F&& func, const State& dep1, const State& ... deps) + { return CreateFuncNode(group, std::forward(func), dep1, deps ...); } // Construct with implicit group template - explicit State(F&& func, const State& dep1, const State& ... deps) : - State::StateInternals( CreateFuncNode(dep1.GetGroup(), std::forward(func), dep1, deps ...) ) - { } + static State Create(F&& func, const State& dep1, const State& ... deps) + { return CreateFuncNode(dep1.GetGroup(), std::forward(func), dep1, deps ...); } + + State() = default; + + State(const State&) = default; + State& operator=(const State&) = default; + + State(State&&) = default; + State& operator=(State&&) = default; auto GetGroup() const -> const Group& { return this->GetNodePtr()->GetGroup(); } @@ -68,13 +66,13 @@ class State : protected REACT_IMPL::StateInternals { return s; } protected: - explicit State(std::shared_ptr>&& nodePtr) : + State(std::shared_ptr>&& nodePtr) : State::StateInternals( std::move(nodePtr) ) { } private: template - auto CreateFuncNode(const Group& group, F&& func, const State& dep1, const State& ... deps) -> decltype(auto) + static auto CreateFuncNode(const Group& group, F&& func, const State& dep1, const State& ... deps) -> decltype(auto) { using REACT_IMPL::StateFuncNode; using REACT_IMPL::SameGroupOrLink; @@ -94,23 +92,23 @@ template class StateVar : public State { public: + // Construct with group + default + static StateVar Create(const Group& group) + { return CreateVarNode(group); } + + // Construct with group + value + template + static StateVar Create(const Group& group, T&& value) + { return CreateVarNode(group, std::forward(value)); } + + StateVar() = default; + StateVar(const StateVar&) = default; StateVar& operator=(const StateVar&) = default; StateVar(StateVar&&) = default; StateVar& operator=(StateVar&&) = default; - // Construct with group + default - explicit StateVar(const Group& group) : - StateVar::State( CreateVarNode(group) ) - { } - - // Construct with group + value - template - StateVar(const Group& group, T&& value) : - StateVar::State( CreateVarNode(group, std::forward(value)) ) - { } - void Set(const S& newValue) { SetValue(newValue); } @@ -128,7 +126,7 @@ class StateVar : public State { return !(a == b); } protected: - explicit StateVar(std::shared_ptr>&& nodePtr) : + StateVar(std::shared_ptr>&& nodePtr) : StateVar::State( std::move(nodePtr) ) { } @@ -182,22 +180,22 @@ template class StateSlot : public State { public: + // Construct with explicit group + static StateSlot Create(const Group& group, const State& input) + { return CreateSlotNode(group, input); } + + // Construct with implicit group + static StateSlot Create(const State& input) + { return CreateSlotNode(input.GetGroup(), input); } + + StateSlot() = default; + StateSlot(const StateSlot&) = default; StateSlot& operator=(const StateSlot&) = default; StateSlot(StateSlot&&) = default; StateSlot& operator=(StateSlot&&) = default; - // Construct with explicit group - StateSlot(const Group& group, const State& input) : - StateSlot::State( CreateSlotNode(group, input) ) - { } - - // Construct with implicit group - explicit StateSlot(const State& input) : - StateSlot::State( CreateSlotNode(input.GetGroup(), input) ) - { } - void Set(const State& newInput) { SetInput(newInput); } @@ -205,7 +203,7 @@ class StateSlot : public State { SetInput(newInput); } protected: - explicit StateSlot(std::shared_ptr>&& nodePtr) : + StateSlot(std::shared_ptr>&& nodePtr) : StateSlot::State( std::move(nodePtr) ) { } @@ -240,18 +238,24 @@ template class StateLink : public State { public: + // Construct with group + static StateLink Create(const Group& group, const State& input) + { return GetOrCreateLinkNode(group, input); } + + StateLink() = default; + StateLink(const StateLink&) = default; StateLink& operator=(const StateLink&) = default; StateLink(StateLink&&) = default; StateLink& operator=(StateLink&&) = default; - // Construct with group - StateLink(const Group& group, const State& input) : - StateLink::State( GetOrCreateLinkNode(group, input) ) +protected: + StateLink(std::shared_ptr>&& nodePtr) : + StateLink::State( std::move(nodePtr) ) { } -protected: +private: static auto GetOrCreateLinkNode(const Group& group, const State& input) -> decltype(auto) { using REACT_IMPL::StateLinkNode; @@ -262,9 +266,7 @@ class StateLink : public State ReactGraph::LinkCache& linkCache = GetInternals(group).GetGraphPtr()->GetLinkCache(); - std::shared_ptr nodePtr = linkCache.LookupOrCreate( - k, - [&] + std::shared_ptr nodePtr = linkCache.LookupOrCreate(k, [&] { auto nodePtr = std::make_shared>(group, input); nodePtr->SetWeakSelfPtr(std::weak_ptr>{ nodePtr }); @@ -275,19 +277,97 @@ class StateLink : public State } }; -/******************************************/ REACT_END /******************************************/ +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// ObjectContext +/////////////////////////////////////////////////////////////////////////////////////////////////// +template +class ObjectContext +{ +public: + ObjectContext() = default; + + ObjectContext(const ObjectContext&) = default; + ObjectContext& operator=(const ObjectContext&) = default; + + ObjectContext(ObjectContext&&) = default; + ObjectContext& operator=(ObjectContext&&) = default; + + const S& GetObject() const + { return object_; } -/***************************************/ REACT_IMPL_BEGIN /**************************************/ + template + const U& Get(const State& member) const + { return GetInternals(member).Value(); } + template + const EventValueList& Get(const Event& member) const + { return GetInternals(member).Events(); } + +private: + template + explicit ObjectContext(Us&& ... args) : + object_( std::forward(args) ... ) + { } + + S object_; + + template + friend class impl::StateNode; +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// ObjectState +/////////////////////////////////////////////////////////////////////////////////////////////////// template -static State SameGroupOrLink(const Group& targetGroup, const State& dep) +class ObjectState : public State> { - if (dep.GetGroup() == targetGroup) - return dep; - else - return StateLink( targetGroup, dep ); -} +public: + // Construct with group + template + static ObjectState Create(const Group& group, S&& obj, const Us& ... members) + { + using REACT_IMPL::NodeId; + + std::initializer_list memberIds = { GetInternals(members).GetNodeId() ... }; + + return CreateObjectStateNode(group, std::move(obj), memberIds); + } + + template + static ObjectState Create(InPlaceTag, const Group& group, Us&& ... args) + { return CreateObjectStateNode(in_place, group, std::forward(args) ...); } + + ObjectState() = default; -/****************************************/ REACT_IMPL_END /***************************************/ + ObjectState(const ObjectState&) = default; + ObjectState& operator=(const ObjectState&) = default; + + ObjectState(ObjectState&&) = default; + ObjectState& operator=(ObjectState&&) = default; + +protected: + ObjectState(std::shared_ptr>>&& nodePtr) : + ObjectState::State( std::move(nodePtr) ) + { } + +private: + static auto CreateObjectStateNode(const Group& group, S&& obj, const std::initializer_list& memberIds) -> decltype(auto) + { + using REACT_IMPL::ObjectStateNode; + + return std::make_shared>(group, std::move(obj), memberIds); + } + + template + static auto CreateObjectStateNode(InPlaceTag, const Group& group, Us&& ... args) -> decltype(auto) + { + using REACT_IMPL::ObjectStateNode; + using REACT_IMPL::SameGroupOrLink; + + return std::make_shared>(in_place, group, std::forward(args) ...); + } +}; + +/******************************************/ REACT_END /******************************************/ #endif // REACT_STATE_H_INCLUDED \ No newline at end of file diff --git a/project/msvc/CppReact.vcxproj b/project/msvc/CppReact.vcxproj index 1867d880..088c482f 100644 --- a/project/msvc/CppReact.vcxproj +++ b/project/msvc/CppReact.vcxproj @@ -22,6 +22,7 @@ {5E56AAB9-4E33-4B9E-A315-E85CEDB75CF1} CppReact 8.1 + CppReact diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 1946c5e0..82b7e451 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -9,15 +9,11 @@ add_subdirectory($ENV{GTEST_DIR} ${CMAKE_CURRENT_BINARY_DIR}/gtest) ### CppReactTest add_executable(CppReactTest - src/EventStreamTest.cpp - src/EventStreamTestQ.cpp - src/MoveTest.cpp - src/ObserverTest.cpp - src/ObserverTestQ.cpp - src/OperationsTest.cpp - src/OperationsTestQ.cpp - src/SignalTest.cpp - src/SignalTestQ.cpp - src/TransactionTest.cpp) + src/algorithm_tests.cpp + src/common_tests.cpp + src/event_tests.cpp + src/observer_tests.cpp + src/state_tests.cpp + src/transaction_tests.cpp) target_link_libraries(CppReactTest CppReact gtest gtest_main) diff --git a/tests/src/algorithm_tests.cpp b/tests/src/algorithm_tests.cpp index 49bd221c..32cac388 100644 --- a/tests/src/algorithm_tests.cpp +++ b/tests/src/algorithm_tests.cpp @@ -24,14 +24,14 @@ TEST(AlgorithmTest, Hold) Group g; - EventSource evt1( g ); + auto evt1 = EventSource::Create(g); State st = Hold(1, evt1); int output = 0; int turns = 0; - Observer obs([&] (int v) + auto obs = Observer::Create([&] (int v) { ++turns; output = v; @@ -60,14 +60,14 @@ TEST(AlgorithmTest, Monitor1) Group g; - StateVar st( g, 1 ); + auto st = StateVar::Create(g, 1); Event evt = Monitor( st ); int output = 0; int turns = 0; - Observer obs([&] (const auto& events) + auto obs = Observer::Create([&] (const auto& events) { ++turns; @@ -98,7 +98,7 @@ TEST(AlgorithmTest, Monitor2) Group g; - StateVar target( g, 10 ); + auto target = StateVar::Create(g, 10); std::vector results; @@ -107,7 +107,7 @@ TEST(AlgorithmTest, Monitor2) { // Observer is created in a nested scope so it gets destructed before the end of this function. - Observer obs([&] (const auto& events) + auto obs = Observer::Create([&] (const auto& events) { for (int e : events) results.push_back(e); @@ -134,15 +134,15 @@ TEST(AlgorithmTest, Snapshot) { Group g; - StateVar sv( g, 1 ); - EventSource<> es( g ); + auto sv = StateVar::Create(g, 1); + auto es = EventSource<>::Create(g); State st = Snapshot( sv, es ); int output = 0; int turns = 0; - Observer obs([&] (int v) + auto obs = Observer::Create([&] (int v) { ++turns; output = v; @@ -166,15 +166,15 @@ TEST(AlgorithmTest, Pulse) { Group g; - StateVar sv( g, 1 ); - EventSource<> es( g ); + auto sv = StateVar::Create(g, 1); + auto es = EventSource<>::Create(g); Event st = Pulse( sv, es ); int output = 0; int turns = 0; - Observer obs([&] (const auto& events) + auto obs = Observer::Create([&] (const auto& events) { for (int e : events) { @@ -201,7 +201,7 @@ TEST(AlgorithmTest, Iterate1) { Group g; - EventSource numSrc( g ); + auto numSrc = EventSource::Create(g); State numFold = Iterate(0, [] (const auto& events, int v) { @@ -214,7 +214,7 @@ TEST(AlgorithmTest, Iterate1) numSrc << i; int output = 0; - Observer obs([&] (int v) { output = v; }, numFold); + auto obs = Observer::Create([&] (int v) { output = v; }, numFold); EXPECT_EQ(output, 5050); } @@ -223,7 +223,7 @@ TEST(AlgorithmTest, Iterate2) { Group g; - EventSource charSrc( g ); + auto charSrc = EventSource::Create(g); State strFold = Iterate(std::string(""), [] (const auto& events, std::string s) { @@ -233,7 +233,7 @@ TEST(AlgorithmTest, Iterate2) }, charSrc); std::string output; - Observer obs([&] (const auto& v) { output = v; }, strFold); + auto obs = Observer::Create([&] (const auto& v) { output = v; }, strFold); charSrc << 'T' << 'e' << 's' << 't'; @@ -244,7 +244,7 @@ TEST(AlgorithmTest, Iterate3) { Group g; - EventSource numSrc( g ); + auto numSrc = EventSource::Create(g); State numFold = Iterate(0, [] (const auto& events, int v) { @@ -256,7 +256,7 @@ TEST(AlgorithmTest, Iterate3) int turns = 0; int output = 0; - Observer obs([&] (const auto& v) + auto obs = Observer::Create([&] (const auto& v) { ++turns; output = v; @@ -298,7 +298,7 @@ TEST(AlgorithmTest, Iterate4) { Group g; - EventSource<> trigger( g ); + auto trigger = EventSource<>::Create(g); { State inc = Iterate(0, Incrementer{ }, trigger); @@ -306,7 +306,7 @@ TEST(AlgorithmTest, Iterate4) trigger.Emit(); int output = 0; - Observer obs([&] (int v) { output = v; }, inc); + auto obs = Observer::Create([&] (int v) { output = v; }, inc); EXPECT_EQ(output, 100); } @@ -317,7 +317,7 @@ TEST(AlgorithmTest, Iterate4) trigger.Emit(); int output = 0; - Observer obs([&] (int v) { output = v; }, dec); + auto obs = Observer::Create([&] (int v) { output = v; }, dec); ASSERT_EQ(output, 100); } @@ -327,7 +327,7 @@ TEST(AlgorithmTest, IterateByRef1) { Group g; - EventSource src( g ); + auto src = EventSource::Create(g); auto x = IterateByRef>(std::vector{ }, [] (const auto& events, auto& v) { @@ -336,7 +336,7 @@ TEST(AlgorithmTest, IterateByRef1) }, src); std::vector output; - Observer obs([&] (const auto& v) { output = v; }, x); + auto obs = Observer::Create([&] (const auto& v) { output = v; }, x); // Push for (int i=1; i<=100; i++) @@ -353,7 +353,7 @@ TEST(AlgorithmTest, IterateByRef2) { Group g; - EventSource<> src( g ); + auto src = EventSource<>::Create(g); auto x = IterateByRef>(std::vector{ }, [] (const auto& events, std::vector& v) { @@ -362,7 +362,7 @@ TEST(AlgorithmTest, IterateByRef2) }, src); std::vector output; - Observer obs([&] (const auto& v) { output = v; }, x); + auto obs = Observer::Create([&] (const auto& v) { output = v; }, x); // Push for (auto i=0; i<100; i++) @@ -392,15 +392,15 @@ TEST(AlgorithmTest, TransformWithState) { Group g; - StateVar in1( g ); - StateVar in2( g ); + auto in1 = StateVar::Create(g); + auto in2 = StateVar::Create(g); - State sum( Sum, in1, in2 ); - State prod( Prod, in1, in2 ); - State diff( Diff, in1, in2 ); + auto sum = State::Create(Sum, in1, in2); + auto prod = State::Create(Prod, in1, in2); + auto diff = State::Create(Diff, in1, in2); - EventSource<> src1( g ); - EventSource src2( g ); + auto src1 = EventSource<>::Create(g); + auto src2 = EventSource::Create(g); auto out1 = Transform>([] (Token, int sum, int prod, int diff) { @@ -418,7 +418,7 @@ TEST(AlgorithmTest, TransformWithState) { std::tuple output1; - Observer obs1([&] (const auto& events) + auto obs1 = Observer::Create([&] (const auto& events) { for (const auto& e : events) { @@ -429,7 +429,7 @@ TEST(AlgorithmTest, TransformWithState) std::tuple output2; - Observer obs2([&] (const auto& events) + auto obs2 = Observer::Create([&] (const auto& events) { for (const auto& e : events) { @@ -460,7 +460,7 @@ TEST(AlgorithmTest, TransformWithState) { std::tuple output1; - Observer obs1([&] (const auto& events) + auto obs1 = Observer::Create([&] (const auto& events) { for (const auto& e : events) { @@ -471,7 +471,7 @@ TEST(AlgorithmTest, TransformWithState) std::tuple output2; - Observer obs2([&] (const auto& events) + auto obs2 = Observer::Create([&] (const auto& events) { for (const auto& e : events) { @@ -504,14 +504,14 @@ TEST(AlgorithmTest, IterateWithState) { Group g; - StateVar in1( g ); - StateVar in2( g ); + auto in1 = StateVar::Create(g); + auto in2 = StateVar::Create(g); - State op1(Sum, in1, in2); - State op2([] (int a, int b) { return (a + b) * 10; }, in1, in2); + auto op1 = State::Create(Sum, in1, in2); + auto op2 = State::Create([] (int a, int b) { return (a + b) * 10; }, in1, in2); - EventSource<> src1( g ); - EventSource src2( g ); + auto src1 = EventSource<>::Create(g); + auto src2 = EventSource::Create(g); auto out1 = Iterate>(std::make_tuple(0, 0), [] (const auto& events, std::tuple t, int op1, int op2) { @@ -536,7 +536,7 @@ TEST(AlgorithmTest, IterateWithState) { std::tuple output1; - Observer obs1([&] (const auto& v) + auto obs1 = Observer::Create([&] (const auto& v) { ++turns1; output1 = v; @@ -544,7 +544,7 @@ TEST(AlgorithmTest, IterateWithState) std::tuple output2; - Observer obs2([&] (const auto& v) + auto obs2 = Observer::Create([&] (const auto& v) { ++turns2; output2 = v; @@ -570,7 +570,7 @@ TEST(AlgorithmTest, IterateWithState) { std::tuple output1; - Observer obs1([&] (const auto& v) + auto obs1 = Observer::Create([&] (const auto& v) { ++turns1; output1 = v; @@ -578,7 +578,7 @@ TEST(AlgorithmTest, IterateWithState) std::tuple output2; - Observer obs2([&] (const auto& v) + auto obs2 = Observer::Create([&] (const auto& v) { ++turns2; output2 = v; @@ -606,14 +606,14 @@ TEST(AlgorithmTest, IterateByRefWithState) { Group g; - StateVar in1( g ); - StateVar in2( g ); + auto in1 = StateVar::Create(g); + auto in2 = StateVar::Create(g); - State op1( Sum, in1, in2 ); - State op2([] (int a, int b) { return (a + b) * 10; }, in1, in2); + auto op1 = State::Create(Sum, in1, in2); + auto op2 = State::Create([] (int a, int b) { return (a + b) * 10; }, in1, in2); - EventSource<> src1( g ); - EventSource src2( g ); + auto src1 = EventSource<>::Create(g); + auto src2 = EventSource::Create(g); auto out1 = IterateByRef>(std::vector{ }, [] (const auto& events, std::vector& v, int op1, int op2) { @@ -640,7 +640,7 @@ TEST(AlgorithmTest, IterateByRefWithState) { std::vector output1; - Observer obs1([&] (const std::vector& v) + auto obs1 = Observer::Create([&] (const std::vector& v) { ++turns1; output1 = v; @@ -648,7 +648,7 @@ TEST(AlgorithmTest, IterateByRefWithState) std::vector output2; - Observer obs2([&] (const std::vector& v) + auto obs2 = Observer::Create([&] (const std::vector& v) { ++turns2; output2 = v; @@ -676,7 +676,7 @@ TEST(AlgorithmTest, IterateByRefWithState) { std::vector output1; - Observer obs1([&] (const std::vector& v) + auto obs1 = Observer::Create([&] (const std::vector& v) { ++turns1; output1 = v; @@ -684,7 +684,7 @@ TEST(AlgorithmTest, IterateByRefWithState) std::vector output2; - Observer obs2([&] (const std::vector& v) + auto obs2 = Observer::Create([&] (const std::vector& v) { ++turns2; output2 = v; diff --git a/tests/src/event_tests.cpp b/tests/src/event_tests.cpp index 168ac619..c4a3200c 100644 --- a/tests/src/event_tests.cpp +++ b/tests/src/event_tests.cpp @@ -25,7 +25,7 @@ TEST(EventTest, Construction) // Event source { - EventSource t1( g ); + auto t1 = EventSource::Create(g); EventSource t2( t1 ); EventSource t3( std::move(t1) ); @@ -37,7 +37,7 @@ TEST(EventTest, Construction) // Event slot { - EventSlot t1( g ); + auto t1 = EventSlot::Create(g); EventSlot t2( t1 ); EventSlot t3( std::move(t1) ); @@ -49,9 +49,9 @@ TEST(EventTest, Construction) // Event link { - EventSlot s1( g ); + auto s1 = EventSlot::Create(g); - EventLink t1( g, s1 ); + auto t1 = EventLink::Create(g, s1); EventLink t2( t1 ); EventLink t3( std::move(t1) ); @@ -66,11 +66,11 @@ TEST(EventTest, BasicOutput) { Group g; - EventSource evt( g ); + auto evt = EventSource::Create(g); int output = 0; - Observer obs([&] (const auto& events) + auto obs = Observer::Create([&] (const auto& events) { for (int e : events) output += e; @@ -89,15 +89,15 @@ TEST(EventTest, Slots) { Group g; - EventSource evt1( g ); - EventSource evt2( g ); + auto evt1 = EventSource::Create(g); + auto evt2 = EventSource::Create(g); - EventSlot slot( g ); + auto slot = EventSlot::Create(g); int output = 0; int turns = 0; - Observer obs([&] (const auto& events) + auto obs = Observer::Create([&] (const auto& events) { ++turns; @@ -153,12 +153,12 @@ TEST(EventTest, Transactions) { Group g; - EventSource evt( g ); + auto evt = EventSource::Create(g); int output = 0; int turns = 0; - Observer obs([&] (const auto& events) + auto obs = Observer::Create([&] (const auto& events) { ++turns; for (int e : events) @@ -182,17 +182,17 @@ TEST(EventTest, Links) Group g2; Group g3; - EventSource evt1( g1 ); - EventSource evt2( g2 ); - EventSource evt3( g3 ); + auto evt1 = EventSource::Create(g1); + auto evt2 = EventSource::Create(g2); + auto evt3 = EventSource::Create(g3); - EventSlot slot( g1 ); + auto slot = EventSlot::Create(g1); // Same group slot.Add(evt1); // Explicit link - EventLink lnk2( g1, evt2 ); + auto lnk2 = EventLink::Create(g1, evt2); slot.Add(lnk2); // Implicit link @@ -203,7 +203,7 @@ TEST(EventTest, Links) EXPECT_EQ(0, output); - Observer obs([&] (const auto& events) + auto obs = Observer::Create([&] (const auto& events) { ++turns; for (int e : events) @@ -224,19 +224,19 @@ TEST(EventTest, EventSources) { Group g; - EventSource es1( g ); - EventSource es2( g ); + auto es1 = EventSource::Create(g); + auto es2 = EventSource::Create(g); std::queue results1; std::queue results2; - Observer obs1([&] (const auto& events) + auto obs1 = Observer::Create([&] (const auto& events) { for (int e : events) results1.push(e); }, es1); - Observer obs2([&] (const auto& events) + auto obs2 = Observer::Create([&] (const auto& events) { for (int e : events) results2.push(e); @@ -280,15 +280,15 @@ TEST(EventTest, Merge1) { Group g; - EventSource a1( g ); - EventSource a2( g ); - EventSource a3( g ); + auto a1 = EventSource::Create(g); + auto a2 = EventSource::Create(g); + auto a3 = EventSource::Create(g); Event merged = Merge(g, a1, a2, a3); std::vector results; - Observer obs1([&] (const auto& events) + auto obs1 = Observer::Create([&] (const auto& events) { for (int e : events) results.push_back(e); @@ -312,15 +312,15 @@ TEST(EventTest, Merge2) { Group g; - EventSource a1( g ); - EventSource a2( g ); - EventSource a3( g ); + auto a1 = EventSource::Create(g); + auto a2 = EventSource::Create(g); + auto a3 = EventSource::Create(g); Event merged = Merge(a1, a2, a3); std::vector results; - Observer obs1([&] (const auto& events) + auto obs1 = Observer::Create([&] (const auto& events) { for (const auto& e : events) results.push_back(e); @@ -348,8 +348,8 @@ TEST(EventTest, Merge3) { Group g; - EventSource a1( g ); - EventSource a2( g ); + auto a1 = EventSource::Create(g); + auto a2 = EventSource::Create(g); Event f1 = Filter([] (int v) { return true; }, a1); Event f2 = Filter([] (int v) { return true; }, a2); @@ -358,7 +358,7 @@ TEST(EventTest, Merge3) std::queue results; - Observer obs1([&] (const auto& events) + auto obs1 = Observer::Create([&] (const auto& events) { for (int e : events) results.push(e); @@ -387,7 +387,7 @@ TEST(EventTest, Filter) { Group g; - EventSource in( g ); + auto in = EventSource::Create(g); std::queue results; @@ -396,7 +396,7 @@ TEST(EventTest, Filter) return s == "Hello World"; }, in); - Observer obs1([&] (const auto& events) + auto obs1 = Observer::Create([&] (const auto& events) { for (const auto& e : events) results.push(e); @@ -417,8 +417,8 @@ TEST(EventTest, Transform) { Group g; - EventSource in1( g ); - EventSource in2( g ); + auto in1 = EventSource::Create(g); + auto in2 = EventSource::Create(g); std::vector results; @@ -430,7 +430,7 @@ TEST(EventTest, Transform) return s; }, merged); - Observer obs1([&] (const auto& events) + auto obs1 = Observer::Create([&] (const auto& events) { for (const auto& e : events) results.push_back(e); @@ -452,13 +452,13 @@ TEST(EventTest, Flow) std::vector results; - EventSource in1( g ); - EventSource in2( g ); + auto in1 = EventSource::Create(g); + auto in2 = EventSource::Create(g); auto merged = Merge(in1, in2); int turns = 0; - Event processed([&] (const auto& events, auto out) + auto processed = Event::Create([&] (const auto& events, auto out) { for (const auto& e : events) { @@ -469,7 +469,7 @@ TEST(EventTest, Flow) ++turns; }, merged); - Observer obs1([&] (const auto& events) + auto obs1 = Observer::Create([&] (const auto& events) { for (float e : events) results.push_back(e); @@ -497,15 +497,15 @@ TEST(EventTest, Join) { Group g; - EventSource in1( g ); - EventSource in2( g ); - EventSource in3( g ); + auto in1 = EventSource::Create(g); + auto in2 = EventSource::Create(g); + auto in3 = EventSource::Create(g); Event> joined = Join(in1, in2, in3); std::vector> results; - Observer obs1([&] (const auto& events) + auto obs1 = Observer::Create([&] (const auto& events) { for (const auto& e : events) results.push_back(e); @@ -536,12 +536,12 @@ TEST(EventTest, FilterWithState) { Group g; - EventSource in( g ); + auto in = EventSource::Create(g); - StateVar sig1( g, 1338 ); - StateVar sig2( g, 1336 ); + auto sig1 = StateVar::Create(g, 1338); + auto sig2 = StateVar::Create(g, 1336); - EventSource in2( g ); + auto in2 = EventSource::Create(g); auto filtered = Filter([] (const std::string& s, int sig1, int sig2) { @@ -550,7 +550,7 @@ TEST(EventTest, FilterWithState) std::queue results; - Observer obs([&] (const auto& events) + auto obs = Observer::Create([&] (const auto& events) { for (const auto& e : events) results.push(e); @@ -573,13 +573,13 @@ TEST(EventTest, TransformWithState) std::vector results; - EventSource in1( g ); - EventSource in2( g ); + auto in1 = EventSource::Create(g); + auto in2 = EventSource::Create(g); Event merged = Merge(in1, in2); - StateVar first( g, "Ace" ); - StateVar last( g, "McSteele" ); + auto first = StateVar::Create(g, "Ace"); + auto last = StateVar::Create(g, "McSteele"); auto transformed = Transform([] (std::string s, const std::string& first, const std::string& last) -> std::string { @@ -588,7 +588,7 @@ TEST(EventTest, TransformWithState) return s; }, merged, first, last); - Observer obs([&] (const auto& events) + auto obs = Observer::Create([&] (const auto& events) { for (const auto& e : events) results.push_back(e); @@ -615,15 +615,15 @@ TEST(EventTest, FlowWithState) std::vector results; - EventSource in1( g ); - EventSource in2( g ); + auto in1 = EventSource::Create(g); + auto in2 = EventSource::Create(g); - StateVar mult( g, 10 ); + auto mult = StateVar::Create(g, 10); Event merged = Merge(in1, in2); int callCount = 0; - Event processed([&] (const auto& events, auto out, int mult) + auto processed = Event::Create([&] (const auto& events, auto out, int mult) { for (const auto& e : events) { @@ -634,7 +634,7 @@ TEST(EventTest, FlowWithState) callCount++; }, merged, mult); - Observer obs([&] (const auto& events) + auto obs = Observer::Create([&] (const auto& events) { for (float e : events) results.push_back(e); diff --git a/tests/src/state_tests.cpp b/tests/src/state_tests.cpp index 953cedc8..10e41205 100644 --- a/tests/src/state_tests.cpp +++ b/tests/src/state_tests.cpp @@ -20,7 +20,7 @@ TEST(StateTest, Construction) // State variable { - StateVar t1( g, 0 ); + auto t1 = StateVar::Create(g, 0); StateVar t2( t1 ); StateVar t3( std::move(t1) ); @@ -32,9 +32,9 @@ TEST(StateTest, Construction) // State slot { - StateVar t0( g, 0 ); + auto t0 = StateVar::Create(g, 0); - StateSlot t1( g, t0 ); + auto t1 = StateSlot::Create(g, t0); StateSlot t2( t1 ); StateSlot t3( std::move(t1) ); @@ -46,11 +46,11 @@ TEST(StateTest, Construction) // State link { - StateVar t0( g, 0 ); + auto t0 = StateVar::Create(g, 0); - StateSlot s1( g, t0 ); + auto s1 = StateSlot::Create(g, t0); - StateLink t1( g, s1 ); + auto t1 = StateLink::Create(g, s1); StateLink t2( t1 ); StateLink t3( std::move(t1) ); @@ -65,11 +65,11 @@ TEST(StateTest, BasicOutput) { Group g; - StateVar st( g ); + auto st = StateVar::Create(g); int output = 0; - Observer obs([&] (const auto& v) + auto obs2 = Observer::Create([&] (const auto& v) { output += v; }, st); @@ -87,15 +87,15 @@ TEST(StateTest, Slots) { Group g; - StateVar st1( g ); - StateVar st2( g ); + auto st1 = StateVar::Create(g); + auto st2 = StateVar::Create(g); - StateSlot slot( g, st1 ); + auto slot = StateSlot::Create(g, st1); int output = 0; int turns = 0; - Observer obs([&] (const auto& v) + auto obs = Observer::Create([&] (const auto& v) { ++turns; output += v; @@ -125,12 +125,12 @@ TEST(StateTest, Transactions) { Group g; - StateVar st( g, 1 ); + auto st = StateVar::Create(g, 1); int output = 0; int turns = 0; - Observer obs([&] (const auto& v) + auto obs = Observer::Create([&] (const auto& v) { ++turns; output += v; @@ -156,16 +156,16 @@ TEST(StateTest, Links) Group g2; Group g3; - StateVar st1( g1, 1 ); - StateVar st2( g2, 2 ); - StateVar st3( g3, 3 ); + auto st1 = StateVar::Create(g1, 1); + auto st2 = StateVar::Create(g2, 2); + auto st3 = StateVar::Create(g3, 3); - StateSlot slot( g1, st1 ); + auto slot = StateSlot::Create(g1, st1); int output = 0; int turns = 0; - Observer obs([&] (const auto& v) + auto obs = Observer::Create([&] (const auto& v) { ++turns; output = v; @@ -177,7 +177,7 @@ TEST(StateTest, Links) EXPECT_EQ(2, turns); // Explicit link - StateLink lnk2( g1, st2 ); + auto lnk2 = StateLink::Create(g1, st2); slot.Set(lnk2); std::this_thread::sleep_for(std::chrono::seconds(1)); EXPECT_EQ(2, output); @@ -223,21 +223,21 @@ TEST(StateTest, StateCombination1) { Group g; - StateVar a( g, 0 ); - StateVar b( g, 0 ); - StateVar c( g, 0 ); + auto a = StateVar::Create(g, 0); + auto b = StateVar::Create(g, 0); + auto c = StateVar::Create(g, 0); - State s1(Sum2, a, b); + auto s1 = State::Create(Sum2, a, b); - State x(Sum2, s1, c); - State y(Sum3, a, b, c); + auto x = State::Create(Sum2, s1, c); + auto y = State::Create(Sum3, a, b, c); int output1 = 0; int output2 = 0; int turns1 = 0; int turns2 = 0; - Observer obs1([&] (int v) + auto obs1 = Observer::Create([&] (int v) { ++turns1; output1 = v; @@ -246,7 +246,7 @@ TEST(StateTest, StateCombination1) EXPECT_EQ(0, output1); EXPECT_EQ(1, turns1); - Observer obs2([&] (int v) + auto obs2 = Observer::Create([&] (int v) { ++turns2; output2 = v; @@ -272,57 +272,57 @@ TEST(StateTest, StateCombination2) std::vector results; - StateVar n1( g, 1 ); + auto n1 = StateVar::Create(g, 1); - State n2([] (int n1) + auto n2 = State::Create([] (int n1) { return n1 + 1; }, n1); - State n3([] (int n1, int n2) + auto n3 = State::Create([] (int n1, int n2) { return n2 + n1 + 1; }, n1, n2); - State n4([] (int n3) + auto n4 = State::Create([] (int n3) { return n3 + 1; }, n3); - State n5([] (int n1, int n3, int n4) + auto n5 = State::Create([] (int n1, int n3, int n4) { return n4 + n3 + n1 + 1; }, n1, n3, n4); - State n6([] (int n5) + auto n6 = State::Create([] (int n5) { return n5 + 1; }, n5); - State n7([] (int n5, int n6) + auto n7 = State::Create([] (int n5, int n6) { return n6 + n5 + 1; }, n5, n6); - State n8([] (int n7) + auto n8 = State::Create([] (int n7) { return n7 + 1; }, n7); - State n9([] (int n1, int n5, int n7, int n8) + auto n9 = State::Create([] (int n1, int n5, int n7, int n8) { return n8 + n7 + n5 + n1 + 1; }, n1, n5, n7, n8); - State n10([] (int n9) + auto n10 = State::Create([] (int n9) { return n9 + 1; }, n9); - State n11([] (int n9, int n10) + auto n11 = State::Create([] (int n9, int n10) { return n10 + n9 + 1; }, n9, n10); - State n12([] (int n11) + auto n12 = State::Create([] (int n11) { return n11 + 1; }, n11); - State n13([] (int n9, int n11, int n12) + auto n13 = State::Create([] (int n9, int n11, int n12) { return n12 + n11 + n9 + 1; }, n9, n11, n12); - State n14([] (int n13) + auto n14 = State::Create([] (int n13) { return n13 + 1; }, n13); - State n15([] (int n13, int n14) + auto n15 = State::Create([] (int n13, int n14) { return n14 + n13 + 1; }, n13, n14); - State n16([] (int n15) + auto n16 = State::Create([] (int n15) { return n15 + 1; }, n15); - State n17([] (int n9, int n13, int n15, int n16) + auto n17 = State::Create([] (int n9, int n13, int n15, int n16) { return n16 + n15 + n13 + n9 + 1; }, n9, n13, n15, n16); - Observer obs([&] (int v) { results.push_back(v); }, n17); + auto obs = Observer::Create([&] (int v) { results.push_back(v); }, n17); n1.Set(10); // 7732 n1.Set(100); // 68572 @@ -342,11 +342,11 @@ TEST(StateTest, Modify1) std::vector results; - StateVar> var( g, std::vector{ } ); + auto var = StateVar>::Create(g, std::vector{ }); int turns = 0; - Observer obs([&] (const std::vector& v) + auto obs = Observer::Create([&] (const std::vector& v) { ++turns; results = v; @@ -372,11 +372,11 @@ TEST(StateTest, Modify2) std::vector results; - StateVar> var( g, std::vector{ } ); + auto var = StateVar>::Create(g, std::vector{ }); int turns = 0; - Observer obs([&] (const std::vector& v) + auto obs = Observer::Create([&] (const std::vector& v) { ++turns; results = v; @@ -402,17 +402,16 @@ TEST(StateTest, Modify3) std::vector results; - StateVar> var( g, std::vector{ } ); + auto var = StateVar>::Create(g, std::vector{ }); int turns = 0; - Observer obs([&] (const std::vector& v) + auto obs = Observer::Create([&] (const std::vector& v) { ++turns; results = v; }, var); - // Also terrible g.DoTransaction([&] { var.Set(std::vector{ 30, 50 }); @@ -424,4 +423,58 @@ TEST(StateTest, Modify3) EXPECT_EQ(results[2], 70); ASSERT_EQ(turns, 2); +} + +class Widget +{ +public: + StateVar color; + + StateVar width; + StateVar height; + + auto GetReactiveMembers() const -> decltype(auto) + { return std::tie(color, width, height); } + + Widget(const Group& group) + { + color = StateVar::Create(group, 0); + width = StateVar::Create(group, 0); + height = StateVar::Create(group, 0); + } + + Widget(const Group& group, int value) + { + color = StateVar::Create(group, value); + width = StateVar::Create(group, value); + height = StateVar::Create(group, value); + } + + +}; + +TEST(StateTest, Object) +{ + Group g; + + Widget w1( g ); + Widget w2( g ); + + auto st1 = ObjectState::Create(g, std::move(w1), w1.color, w1.width, w1.height); + + auto st2 = ObjectState::Create(in_place, g, 1337); + + auto st3 = ObjectState::Create(g, std::move(w2)); + + auto obs = Observer::Create([&] (const auto& ctx) + { + const Widget& widget = ctx.GetObject(); + + int color = ctx.Get(widget.color); + int width = ctx.Get(widget.width); + int height = ctx.Get(widget.height); + }, st1); + + w1.color.Set(10); + w2.color.Set(20); } \ No newline at end of file diff --git a/tests/src/transaction_tests.cpp b/tests/src/transaction_tests.cpp index 01e65ac9..6c0f8101 100644 --- a/tests/src/transaction_tests.cpp +++ b/tests/src/transaction_tests.cpp @@ -19,12 +19,12 @@ TEST(TransactionTest, Merging) { Group g; - EventSource evt( g ); + auto evt = EventSource::Create(g); int output = 0; int turns = 0; - Observer obs([&] (const auto& events) + auto obs = Observer::Create([&] (const auto& events) { ++turns; for (int e : events) @@ -78,12 +78,12 @@ TEST(TransactionTest, LinkedSync) Group g2; Group g3; - EventSource evt1( g1 ); + auto evt1 = EventSource::Create(g1); int output1 = 0; int turns1 = 0; - Observer obs1([&] (const auto& events) + auto obs1 = Observer::Create([&] (const auto& events) { ++turns1; for (int e : events) @@ -95,7 +95,7 @@ TEST(TransactionTest, LinkedSync) int output2 = 0; int turns2 = 0; - Observer obs2([&] (const auto& events) + auto obs2 = Observer::Create([&] (const auto& events) { ++turns2; for (int e : events) @@ -107,7 +107,7 @@ TEST(TransactionTest, LinkedSync) int output3 = 0; int turns3 = 0; - Observer obs3([&] (const auto& events) + auto obs3 = Observer::Create([&] (const auto& events) { std::this_thread::sleep_for(std::chrono::seconds(1)); @@ -147,12 +147,12 @@ TEST(TransactionTest, LinkedSyncMerging) Group g1; Group g2; - EventSource evt1( g1 ); + auto evt1 = EventSource::Create(g1); int output1 = 0; int turns1 = 0; - Observer obs1([&] (const auto& events) + auto obs1 = Observer::Create([&] (const auto& events) { ++turns1; for (int e : events) @@ -164,7 +164,7 @@ TEST(TransactionTest, LinkedSyncMerging) int output2 = 0; int turns2 = 0; - Observer obs2([&] (const auto& events) + auto obs2 = Observer::Create([&] (const auto& events) { std::this_thread::sleep_for(std::chrono::seconds(1)); From 9fe1af70f4910216132f7aec109f11d92d8e6ef8 Mon Sep 17 00:00:00 2001 From: schlangster Date: Mon, 30 Oct 2017 22:02:12 +0100 Subject: [PATCH 59/75] Commented out benchmarks for now. --- benchmarks/src/BenchmarkBase.h | 2 +- benchmarks/src/BenchmarkFanout.h | 8 ++++++-- benchmarks/src/BenchmarkGrid.h | 13 +++++++++++-- benchmarks/src/BenchmarkRandom.h | 11 +++++++---- benchmarks/src/BenchmarkSequence.h | 8 ++++++-- 5 files changed, 31 insertions(+), 11 deletions(-) diff --git a/benchmarks/src/BenchmarkBase.h b/benchmarks/src/BenchmarkBase.h index d27d64b1..6684c062 100644 --- a/benchmarks/src/BenchmarkBase.h +++ b/benchmarks/src/BenchmarkBase.h @@ -14,7 +14,7 @@ #include #include -#include "react/common/Util.h" +#include "react/common/utility.h" /////////////////////////////////////////////////////////////////////////////////////////////////// // Get unique random numbers from range. diff --git a/benchmarks/src/BenchmarkFanout.h b/benchmarks/src/BenchmarkFanout.h index a4855d0f..099f26d2 100644 --- a/benchmarks/src/BenchmarkFanout.h +++ b/benchmarks/src/BenchmarkFanout.h @@ -6,6 +6,8 @@ #pragma once +#if 0 + #ifndef CPP_REACT_BENCHMARK_FANOUT_H #define CPP_REACT_BENCHMARK_FANOUT_H @@ -15,7 +17,7 @@ #include "BenchmarkBase.h" -#include "react/Signal.h" +#include "react/state.h" /* using namespace react; @@ -84,4 +86,6 @@ struct Benchmark_Fanout */ -#endif // CPP_REACT_BENCHMARK_FANOUT_H \ No newline at end of file +#endif // CPP_REACT_BENCHMARK_FANOUT_H + +#endif \ No newline at end of file diff --git a/benchmarks/src/BenchmarkGrid.h b/benchmarks/src/BenchmarkGrid.h index 8f17d6f2..ad2d90af 100644 --- a/benchmarks/src/BenchmarkGrid.h +++ b/benchmarks/src/BenchmarkGrid.h @@ -6,6 +6,11 @@ #pragma once +#if 0 + +#ifndef REACT_BENCHMARK_GRID_H +#define REACT_BENCHMARK_GRID_H + #include #include #include @@ -14,7 +19,7 @@ #include "BenchmarkBase.h" -#include "react/Signal.h" +#include "react/state.h" using namespace react; @@ -159,4 +164,8 @@ struct Benchmark_Grid return d; } -}; \ No newline at end of file +}; + +#endif // REACT_BENCHMARK_GRID_H + +#endif \ No newline at end of file diff --git a/benchmarks/src/BenchmarkRandom.h b/benchmarks/src/BenchmarkRandom.h index cec422da..80257410 100644 --- a/benchmarks/src/BenchmarkRandom.h +++ b/benchmarks/src/BenchmarkRandom.h @@ -6,16 +6,17 @@ #pragma once +#if 0 + #include #include #include #include #include "BenchmarkBase.h" -#include "react/common/Types.h" -#include "react/Group.h" -#include "react/Signal.h" +#include "react/group.h" +#include "react/state.h" using namespace react; /* @@ -320,4 +321,6 @@ struct Benchmark_Random return d; } -};*/ \ No newline at end of file +};*/ + +#endif \ No newline at end of file diff --git a/benchmarks/src/BenchmarkSequence.h b/benchmarks/src/BenchmarkSequence.h index 705e8f58..f02c4890 100644 --- a/benchmarks/src/BenchmarkSequence.h +++ b/benchmarks/src/BenchmarkSequence.h @@ -6,13 +6,15 @@ #pragma once +#if 0 + #include #include #include #include "BenchmarkBase.h" -#include "react/Signal.h" +#include "react/state.h" /* @@ -77,4 +79,6 @@ struct Benchmark_Sequence return d; } -};*/ \ No newline at end of file +};*/ + +#endif \ No newline at end of file From 35cea007cd3715eb97eccfed06d38808a7c9fd64 Mon Sep 17 00:00:00 2001 From: schlangster Date: Mon, 30 Oct 2017 22:02:52 +0100 Subject: [PATCH 60/75] Fixed examples. --- benchmarks/src/Main.cpp | 36 ----- examples/src/BasicAlgorithms.cpp | 197 +++++++++++++++----------- examples/src/BasicComposition.cpp | 148 ++++++------------- examples/src/BasicEvents.cpp | 75 ++++------ examples/src/BasicObservers.cpp | 53 ++----- examples/src/BasicSignals.cpp | 83 +++++------ examples/src/BasicSynchronization.cpp | 159 ++++++--------------- 7 files changed, 287 insertions(+), 464 deletions(-) diff --git a/benchmarks/src/Main.cpp b/benchmarks/src/Main.cpp index a191ccbc..d8bc4d76 100644 --- a/benchmarks/src/Main.cpp +++ b/benchmarks/src/Main.cpp @@ -4,7 +4,6 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -//#define REACT_ENABLE_LOGGING #if 0 //#include "tbb/tick_count.h" //#include "tbb/tbbmalloc_proxy.h" @@ -218,46 +217,11 @@ int main() //runBenchmarks(); //debugBenchmarks(); //profileBenchmark(); - - } -struct Data -{ - State a; - State b; - - State (a, b); -}; - #endif -#include "react/common/expected.h" -#include "react/state.h" -#include "react/event.h" -#include "react/algorithm.h" -#include - -#define unwind_on_error(x) if (!x) return UnwindExpected(std::move(x)); - -using namespace react; - - int main() { - Group g; - - VarSignal t1(g); - VarSignal t2(g); - - EventSource e1(g); - EventSource e2(g); - - auto h1 = Hold(1, e1); - auto h2 = Hold(2, e2); - - auto m1 = Monitor(t1); - auto it1 = Iterate(10, [] (EventRange evnts, int b) { return b; }, e1); - return 0; } \ No newline at end of file diff --git a/examples/src/BasicAlgorithms.cpp b/examples/src/BasicAlgorithms.cpp index 93235700..d6f8aced 100644 --- a/examples/src/BasicAlgorithms.cpp +++ b/examples/src/BasicAlgorithms.cpp @@ -9,10 +9,10 @@ #include #include -#include "react/Signal.h" -#include "react/Event.h" -#include "react/Observer.h" -#include "react/Algorithm.h" +#include "react/state.h" +#include "react/event.h" +#include "react/observer.h" +#include "react/algorithm.h" /////////////////////////////////////////////////////////////////////////////////////////////////// /// Example 1 - Converting events to signals @@ -22,33 +22,35 @@ namespace example1 using namespace std; using namespace react; - Group group; + Group g; struct Sensor { - EventSource samples { group }; - Signal lastSample = Hold(0, samples); + EventSource samples = EventSource::Create(g); + State lastSample = Hold(0, samples); + + auto GetReactiveMembers() const -> decltype(auto) + { return std::tie(lastSample); } }; void Run() { cout << "Example 1 - Converting events to signals" << endl; - Sensor mySensor; + auto sensor = ObjectState::Create(g, Sensor{ }); - Observer obs( - [] (int v) + auto obs = Observer::Create(g, [] (const auto& ctx) { - cout << v << endl; - }, - mySensor.lastSample); + const Sensor& obj = ctx.GetObject(); + cout << ctx.Get(obj.lastSample) << endl; + }, sensor); - mySensor.samples << 20 << 21 << 21 << 22; // output: 20, 21, 22 + sensor->samples << 20 << 21 << 21 << 22; // output: 20, 21, 22 - group.DoTransaction([&] - { - mySensor.samples << 30 << 31 << 31 << 32; - }); // output: 32 + g.DoTransaction([&] + { + sensor->samples << 30 << 31 << 31 << 32; + }); // output: 32 cout << endl; } @@ -62,12 +64,12 @@ namespace example2 using namespace std; using namespace react; - Group group; + Group g; struct Employee { - VarSignal name { group, string( "Bob" ) }; - VarSignal salary { group, 3000 }; + StateVar name = StateVar::Create(g, string( "Bob" )); + StateVar salary = StateVar::Create(g, 66666); }; void Run() @@ -76,13 +78,13 @@ namespace example2 Employee bob; - Observer obs( - [] (EventRange in, const string& name) + auto obs = Observer::Create([] (const auto& events, const string& name) { - for (int newSalary : in) + for (int newSalary : events) cout << name << " now earns " << newSalary << endl; - }, - Monitor(bob.salary), bob.name); + }, Monitor(bob.salary), bob.name); + + bob.salary.Set(66667); cout << endl; } @@ -96,21 +98,18 @@ namespace example3 using namespace std; using namespace react; - Group group; + Group g; struct Counter { - EventSource<> increment { group }; + EventSource<> increment = EventSource<>::Create(g); - Signal count = Iterate( - 0, - [] (EventRange<> in, int count) + State count = Iterate(0, [] (const auto& events, int count) { - for (auto _ : in) + for (auto e : events) ++count; return count; - }, - increment); + }, increment); }; void Run() @@ -123,7 +122,10 @@ namespace example3 myCounter.increment.Emit(); myCounter.increment.Emit(); - cout << myCounter.count.Value() << endl; // output: 3 + auto obs = Observer::Create([] (int v) + { + cout << v << endl; // output: 3 + }, myCounter.count); cout << endl; } @@ -137,33 +139,34 @@ namespace example4 using namespace std; using namespace react; - Group group; + Group g; struct Sensor { - EventSource input{ group }; + EventSource input = EventSource::Create(g); - Signal count = Iterate( - 0, - [] (EventRange in, int count) + State count = Iterate(0, [] (const auto& events, int count) { - for (auto _ : in) - count++; + for (auto e : events) + ++count; return count; - }, - input); + }, input); - Signal sum = Iterate( - 0.0f, - [] (EventRange in, float sum) + State sum = Iterate(0.0f, [] (const auto& events, float sum) { - for (auto v : in) - sum += v; + for (auto e : events) + sum += e; return sum; - }, - input); + }, input); - VarSignal average{ group }; + State average = State::Create([] (int c, float s) + { + if (c != 0) + return s / c; + else + return 0.0f; + + }, count, sum); }; void Run() @@ -174,7 +177,10 @@ namespace example4 mySensor.input << 10.0f << 5.0f << 10.0f << 8.0f; - cout << "Average: " << mySensor.average.Value() << endl; // output: 8.25 + auto obs = Observer::Create([] (float v) + { + cout << "Average: " << v << endl; // output: 8.25 + }, mySensor.average); cout << endl; } @@ -188,16 +194,16 @@ namespace example5 using namespace std; using namespace react; - Group group; + Group g; enum ECmd { increment, decrement, reset }; class Counter { private: - static int DoCounterLoop(EventRange in, int count, int delta, int start) + static int DoCounterLoop(const EventValueList& cmds, int count, int delta, int start) { - for (int cmd : in) + for (int cmd : cmds) { if (cmd == increment) count += delta; @@ -211,12 +217,12 @@ namespace example5 } public: - EventSource update{ group }; + EventSource update = EventSource::Create(g); - VarSignal delta{ group, 1 }; - VarSignal start{ group, 0 }; + StateVar delta = StateVar::Create(g, 1); + StateVar start = StateVar::Create(g, 0); - Signal count{ Iterate(start.Value(), DoCounterLoop, update, delta, start) }; + State count = Iterate(0, DoCounterLoop, update, delta, start); }; void Run() @@ -225,23 +231,44 @@ namespace example5 Counter myCounter; - cout << "Start: " << myCounter.count.Value() << endl; // output: 0 + { + auto obs = Observer::Create([] (int v) + { + cout << "Start: " << v << endl; // output: 0 + }, myCounter.count); + } + myCounter.update.Emit(increment); myCounter.update.Emit(increment); myCounter.update.Emit(increment); - cout << "3x increment by 1: " << myCounter.count.Value() << endl; // output: 3 + { + auto obs = Observer::Create([] (int v) + { + cout << "3x increment by 1: " << v << endl; // output: 3 + }, myCounter.count); + } - myCounter.delta <<= 5; + myCounter.delta.Set(5); myCounter.update.Emit(decrement); - cout << "1x decrement by 5: " << myCounter.count.Value() << endl; // output: -2 + { + auto obs = Observer::Create([] (int v) + { + cout << "1x decrement by 5: " << v << endl; // output: -2 + }, myCounter.count); + } - myCounter.start <<= 100; + myCounter.start.Set(100); myCounter.update.Emit(reset); - cout << "reset to 100: " << myCounter.count.Value() << endl; // output: 100 + { + auto obs = Observer::Create([] (int v) + { + cout << "reset to 100: " << v << endl; // output: 100 + }, myCounter.count); + } cout << endl; } @@ -255,32 +282,32 @@ namespace example6 using namespace std; using namespace react; - Group group; + Group g; class Sensor { private: - static void DoIterateAllSamples(EventRange in, vector& all) + static void DoIterateAllSamples(const EventValueList& events, vector& all) { - for (int input : in) + for (int input : events) all.push_back(input); } - static void DoIterateCritSamples(EventRange in, vector& critical, int threshold) + static void DoIterateCritSamples(const EventValueList events, vector& critical, int threshold) { - for (int input : in) + for (int input : events) if (input > threshold) critical.push_back(input); } public: - EventSource input{ group }; + EventSource input = EventSource::Create(g); - VarSignal threshold{ group, 42 }; + StateVar threshold = StateVar::Create(g, 42); - Signal> allSamples{ Iterate>(vector{ }, DoIterateAllSamples, input) }; + State> allSamples = IterateByRef>(vector{ }, DoIterateAllSamples, input); - Signal> criticalSamples{ Iterate>(vector{ }, DoIterateCritSamples, input, threshold) }; + State> criticalSamples = IterateByRef>(vector{ }, DoIterateCritSamples, input, threshold); }; void Run() @@ -292,15 +319,23 @@ namespace example6 mySensor.input << 40 << 29 << 43 << 50; cout << "All samples: "; - for (auto const& v : mySensor.allSamples.Value()) - cout << v << " "; + { + auto obs = Observer::Create([] (const auto& allSamples) + { + for (auto const& v : allSamples) + cout << v << " "; + }, mySensor.allSamples); + } cout << endl; cout << "Critical samples: "; - for (auto const& v : mySensor.criticalSamples.Value()) - cout << v << " "; - cout << endl; - + { + auto obs = Observer::Create([] (const auto& criticalSamples) + { + for (auto const& v : criticalSamples) + cout << v << " "; + }, mySensor.criticalSamples); + } cout << endl; } } diff --git a/examples/src/BasicComposition.cpp b/examples/src/BasicComposition.cpp index e2fbf3b1..acec053e 100644 --- a/examples/src/BasicComposition.cpp +++ b/examples/src/BasicComposition.cpp @@ -8,10 +8,9 @@ #include #include -#include "react/Domain.h" -#include "react/Signal.h" -#include "react/Event.h" -#include "react/Observer.h" +#include "react/state.h" +#include "react/event.h" +#include "react/observer.h" /////////////////////////////////////////////////////////////////////////////////////////////////// /// Example 1 - Reactive class members @@ -21,155 +20,99 @@ namespace example1 using namespace std; using namespace react; - REACTIVE_DOMAIN(D, sequential) + Group g; class Shape { public: - USING_REACTIVE_DOMAIN(D) + StateVar width = StateVar::Create(g, 0); + StateVar height = StateVar::Create(g, 0); - VarSignalT Width = MakeVar(0); - VarSignalT Height = MakeVar(0); + State size = State::Create(g, CalcSize, width, height); - SignalT Size = Width * Height; + auto GetReactiveMembers() const -> decltype(auto) + { return std::tie(width, height, size); } - EventSourceT<> HasMoved = MakeEventSource(); + private: + static int CalcSize(int w, int h) + { return w * h; } }; void Run() { cout << "Example 1 - Reactive class members" << endl; - Shape myShape; + auto myShape = ObjectState::Create(g, Shape()); - Observe(myShape.Size, [] (int newValue) { - cout << "Size changed to " << newValue << endl; - }); + auto obs = Observer::Create([] (const auto& ctx) + { + const Shape& shape = ctx.GetObject(); + cout << "Size is " << ctx.Get(shape.size) << endl; + }, myShape); - DoTransaction([&] { - myShape.Width <<= 4; - myShape.Height <<= 4; - }); // output: Size changed to 16 + g.DoTransaction([&] + { + myShape->width.Set(4); + myShape->height.Set(4); + }); // output: Size changed to 16 cout << endl; } } /////////////////////////////////////////////////////////////////////////////////////////////////// -/// Example 2 - Signals of references +/// Example 2 - Slots /////////////////////////////////////////////////////////////////////////////////////////////////// namespace example2 { using namespace std; using namespace react; - REACTIVE_DOMAIN(D, sequential) + Group g; class Company { public: - const char* Name; + StateVar name; Company(const char* name) : - Name( name ) - {} + name( StateVar::Create(g, name) ) + { } - // Note: To be used as a signal value type, - // values of the type must be comparable bool operator==(const Company& other) const - { - return this == &other; - } + { return name == other.name; } }; class Employee { public: - USING_REACTIVE_DOMAIN(D) + StateSlot myCompanyName; - VarSignalT MyCompany; + Employee(const Company& company) : + myCompanyName( StateSlot::Create(company.name) ) + { } - Employee(Company& company) : - MyCompany( MakeVar(ref(company)) ) - {} + void SetCompany(const Company& company) + { myCompanyName.Set(company.name); } }; void Run() { - cout << "Example 2 - Signals of references" << endl; + cout << "Example 2 - Slots" << endl; - Company company1( "MetroTec" ); - Company company2( "ACME" ); - - Employee bob( company1 ); - - Observe(bob.MyCompany, [] (const Company& company) { - cout << "Bob works for " << company.Name << endl; - }); - - bob.MyCompany <<= ref(company2); // output: Bob now works for ACME - - cout << endl; - } -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Example 3 - Dynamic signal references -/////////////////////////////////////////////////////////////////////////////////////////////////// -namespace example3 -{ - using namespace std; - using namespace react; - - REACTIVE_DOMAIN(D, sequential) - - class Company - { - public: - USING_REACTIVE_DOMAIN(D) - - VarSignalT Name; - - Company(const char* name) : - Name( MakeVar(string( name )) ) - {} - - bool operator==(const Company& other) const - { - return this == &other; - } - }; - - class Employee - { - public: - USING_REACTIVE_DOMAIN(D) - - VarSignalT MyCompany; - - Employee(Company& company) : - MyCompany( MakeVar(ref(company)) ) - {} - }; - - void Run() - { - cout << "Example 3 - Dynamic signal references" << endl; - - Company company1( "MetroTec" ); - Company company2( "ACME" ); + Company company1( "MetroTec" ); + Company company2( "ACME" ); Employee alice( company1 ); - auto obs = Observe( - REACTIVE_REF(alice.MyCompany, Name), - [] (const string& name) { + auto obs = Observer::Create([] (const string& name) + { cout << "Alice now works for " << name << endl; - }); + }, alice.myCompanyName); - company1.Name <<= string( "ModernTec" ); // output: Alice now works for ModernTec - alice.MyCompany <<= ref(company2); // output: Alice now works for ACME - company2.Name <<= string( "A.C.M.E." ); // output: Alice now works for A.C.M.E. + company1.name.Set(string( "ModernTec" )); // output: Alice now works for ModernTec + alice.SetCompany(company2); // output: Alice now works for ACME + company2.name.Set(string( "A.C.M.E." )); // output: Alice now works for A.C.M.E. cout << endl; } @@ -181,10 +124,7 @@ namespace example3 int main() { example1::Run(); - example2::Run(); - example3::Run(); - return 0; } \ No newline at end of file diff --git a/examples/src/BasicEvents.cpp b/examples/src/BasicEvents.cpp index 53e97984..98fe1ef3 100644 --- a/examples/src/BasicEvents.cpp +++ b/examples/src/BasicEvents.cpp @@ -27,19 +27,17 @@ namespace example1 // An event source that emits values of type string namespace v1 { - EventSource mySource( group ); + EventSource mySource = EventSource::Create(group); void Run() { cout << "Example 1 - Hello world (string source)" << endl; - Observer obs( - [] (EventRange in) + auto obs = Observer::Create([] (const auto& events) { - for (const auto& s : in) - cout << s << std::endl; - }, - mySource); + for (const auto& e : events) + cout << e << std::endl; + }, mySource); mySource << string("Hello world #1"); @@ -53,7 +51,7 @@ namespace example1 // An event source without an explicit value type namespace v2 { - EventSource<> helloWorldTrigger( group ); + EventSource<> helloWorldTrigger = EventSource<>::Create(group); void Run() { @@ -61,13 +59,11 @@ namespace example1 int count = 0; - Observer obs( - [&] (EventRange<> in) + auto obs = Observer::Create([&] (const auto& events) { - for (auto t : in) + for (auto t : events) cout << "Hello world #" << ++count << endl; - }, - helloWorldTrigger); + }, helloWorldTrigger); helloWorldTrigger.Emit(); @@ -90,8 +86,8 @@ namespace example2 Group group; // An event stream that merges both sources - EventSource<> leftClick( group ); - EventSource<> rightClick( group ); + EventSource<> leftClick = EventSource<>::Create(group); + EventSource<> rightClick = EventSource<>::Create(group); Event<> anyClick = Merge(leftClick, rightClick); @@ -101,13 +97,11 @@ namespace example2 int count = 0; - Observer obs( - [&] (EventRange<> in) + auto obs = Observer::Create([&] (const auto& events) { - for (auto t : in) + for (auto t : events) cout << "clicked #" << ++count << endl; - }, - anyClick); + }, anyClick); leftClick.Emit(); // output: clicked #1 rightClick.Emit(); // output: clicked #2 @@ -126,7 +120,7 @@ namespace example3 Group group; - EventSource numbers( group ); + EventSource numbers = EventSource::Create(group); Event greater10 = Filter([] (int n) { return n > 10; }, numbers); @@ -134,13 +128,11 @@ namespace example3 { cout << "Example 3 - Filtering events" << endl; - Observer obs( - [&] (EventRange in) + auto obs = Observer::Create([&] (const auto& events) { - for (auto n : in) + for (auto n : events) cout << n << endl; - }, - greater10); + }, greater10); numbers << 5 << 11 << 7 << 100; // output: 11, 100 @@ -162,34 +154,30 @@ namespace example4 enum class Tag { normal, critical }; using TaggedNum = pair; - EventSource numbers( group ); + EventSource numbers = EventSource::Create(group); - Event tagged = Transform( - [] (int n) + Event tagged = Transform([] (int n) { if (n > 10) return TaggedNum( Tag::critical, n ); else return TaggedNum( Tag::normal, n ); - }, - numbers); + }, numbers); void Run() { cout << "Example 4 - Transforming events" << endl; - Observer obs( - [] (EventRange in) + auto obs = Observer::Create([] (const auto& events) { - for (TaggedNum e : in) + for (TaggedNum e : events) { if (e.first == Tag::critical) cout << "(critical) " << e.second << endl; else cout << "(normal) " << e.second << endl; } - }, - tagged); + }, tagged); numbers << 5; // output: (normal) 5 numbers << 20; // output: (critical) 20 @@ -208,25 +196,24 @@ namespace example5 Group group; - EventSource src( group ); + EventSource src = EventSource::Create(group); void Run() { cout << "Example 5 - Queuing multiple inputs" << endl; - Observer obs( - [] (EventRange in) + auto obs = Observer::Create([] (const auto& events) { - for (int e : in) + for (int e : events) cout << e << endl; }, src); // output: 1, 2, 3, 4 group.DoTransaction([] - { - src << 1 << 2 << 3; - src << 4; - }); + { + src << 1 << 2 << 3; + src << 4; + }); cout << endl; } diff --git a/examples/src/BasicObservers.cpp b/examples/src/BasicObservers.cpp index 8eb03b81..54b24857 100644 --- a/examples/src/BasicObservers.cpp +++ b/examples/src/BasicObservers.cpp @@ -8,9 +8,9 @@ #include #include -#include "react/Signal.h" -#include "react/Event.h" -#include "react/Observer.h" +#include "react/state.h" +#include "react/event.h" +#include "react/observer.h" /////////////////////////////////////////////////////////////////////////////////////////////////// /// Example 1 - Creating subject-bound observers @@ -22,55 +22,21 @@ namespace example1 Group group; - VarSignal x( group, 1 ); + StateVar x = StateVar::Create(group, 1); void Run() { - cout << "Example 1 - Creating subject-bound observers (v1)" << endl; + cout << "Example 1 - Creating observers" << endl; { - Signal mySignal( [] (int x) { return x; }, x ); + auto st = State::Create([] (int x) { return x; }, x); - Observer obs( [] (int mySignal) { cout << mySignal << endl; }, mySignal ); + auto obs = Observer::Create([] (int v) { cout << v << endl; }, st); - x <<= 2; // output: 2 + x.Set(2); // output: 2 } - x <<= 3; // no ouput - - cout << endl; - } -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Example 2 - Detaching observers manually -/////////////////////////////////////////////////////////////////////////////////////////////////// -namespace example2 -{ - using namespace std; - using namespace react; - - Group group; - - EventSource<> trigger( group ); - - void Run() - { - cout << "Example 2 - Detaching observers manually" << endl; - - { - Observer obs( - [] (EventRange<> in) - { - for (auto _ : in) - cout << "Triggered!" << endl; - }, - trigger); - - trigger.Emit(); // output: Triggered! - } - - trigger.Emit(); // no output + x.Set(3); // no ouput cout << endl; } @@ -82,7 +48,6 @@ namespace example2 int main() { example1::Run(); - example2::Run(); return 0; } \ No newline at end of file diff --git a/examples/src/BasicSignals.cpp b/examples/src/BasicSignals.cpp index 749116c8..c743de83 100644 --- a/examples/src/BasicSignals.cpp +++ b/examples/src/BasicSignals.cpp @@ -11,8 +11,8 @@ #include #include -#include "react/Signal.h" -#include "react/Observer.h" +#include "react/state.h" +#include "react/observer.h" /////////////////////////////////////////////////////////////////////////////////////////////////// /// Example 1 - Hello world @@ -35,21 +35,20 @@ namespace example1 Group group; // The two words - VarSignal firstWord( group, string("Change") ); - VarSignal secondWord( group, string("me!") ); + StateVar firstWord = StateVar::Create(group, string("Change")); + StateVar secondWord = StateVar::Create(group, string("me!")); // A signal that concatenates both words - Signal bothWords(ConcatFunc, firstWord, secondWord); + State bothWords = State::Create(ConcatFunc, firstWord, secondWord); void Run() { - Observer obs{ PrintFunc, bothWords }; + auto obs = Observer::Create(PrintFunc, bothWords); cout << "Example 1 - Hello world" << endl; - firstWord <<= string("Hello"); - - secondWord <<= string("World"); + firstWord.Set(string("Hello")); + secondWord.Set(string("World")); cout << endl; } @@ -65,22 +64,21 @@ namespace example2 Group group; - VarSignal x( group, 1 ); + StateVar x = StateVar::Create(group, 1); - Signal xAbs( [] (int v) { return abs(v); }, x); + State xAbs = State::Create([] (int v) { return abs(v); }, x); void Run() { cout << "Example 2 - Reacting to value changes" << endl; - Observer obs( - [] (int newValue) { cout << "xAbs changed to " << newValue << endl; }, - xAbs ); + auto obs = Observer::Create([] (int newValue) + { cout << "xAbs changed to " << newValue << endl; }, xAbs); // 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 + x.Set(2); // output: xAbs changed to 2 + x.Set(-3); // output: xAbs changed to 3 + x.Set(3); // no output, xAbs is still 3 cout << endl; } @@ -99,29 +97,28 @@ namespace example3 Group group; - VarSignal a( group, 1 ); - VarSignal b( group, 1 ); + StateVar a = StateVar::Create(group, 1); + StateVar b = StateVar::Create(group, 1); - Signal x( sumFunc, a, b ); - Signal y( sumFunc, a, b ); - Signal z( sumFunc, x, y ); + State x = State::Create(sumFunc, a, b); + State y = State::Create(sumFunc, a, b); + State z = State::Create(sumFunc, x, y); void Run() { cout << "Example 3 - Changing multiple inputs" << endl; - Observer obs( - [] (int newValue) { cout << "z changed to " << newValue << endl; }, - z ); + auto obs = Observer::Create([] (int newValue) + { cout << "z changed to " << newValue << endl; }, z); - a <<= 2; // output: z changed to 6 - b <<= 2; // output: z changed to 8 + a.Set(2); // output: z changed to 6 + b.Set(2); // output: z changed to 8 group.DoTransaction([&] - { - a <<= 4; - b <<= 4; - }); // output: z changed to 16 + { + a.Set(4); + b.Set(4); + }); // output: z changed to 16 cout << endl; } @@ -137,7 +134,7 @@ namespace example4 Group group; - VarSignal> data( group ); + StateVar> data = StateVar>::Create(group); void Run() { @@ -149,8 +146,13 @@ namespace example4 data.Modify([] (vector& data) { data.push_back("World"); }); -// for (const auto& s : data.Value()) -// cout << s << " "; + auto obs = Observer::Create([] (const vector& data) + { + for (const auto& s : data) + cout << s << " "; + }, data); + + cout << endl; // output: Hello World @@ -185,12 +187,11 @@ namespace example5 } // Input operands - VarSignal a( group, 1 ); - VarSignal b( group, 2 ); + StateVar a = StateVar::Create(group, 1); + StateVar b = StateVar::Create(group, 2); // The expression vector - Signal expressions( - [] (int a, int b) + State expressions = State::Create([] (int a, int b) { ExprVectType result; result.push_back(make_pair(MakeExprStr(a, b, "+"), a + b)); @@ -203,10 +204,10 @@ namespace example5 { cout << "Example 5 - Complex signals (v3)" << endl; - Observer obs(PrintExpressions, expressions); + auto obs = Observer::Create(PrintExpressions, expressions); - a <<= 50; - b <<= 60; + a.Set(50); + b.Set(60); cout << endl; } diff --git a/examples/src/BasicSynchronization.cpp b/examples/src/BasicSynchronization.cpp index 701b5001..d5b29de7 100644 --- a/examples/src/BasicSynchronization.cpp +++ b/examples/src/BasicSynchronization.cpp @@ -8,10 +8,9 @@ #include "tbb/tick_count.h" -#include "react/Domain.h" -#include "react/Signal.h" -#include "react/Event.h" -#include "react/Observer.h" +#include "react/state.h" +#include "react/event.h" +#include "react/observer.h" /////////////////////////////////////////////////////////////////////////////////////////////////// /// Example 1 - Asynchronous transactions @@ -21,50 +20,41 @@ namespace example1 using namespace react; using namespace std; - Group<> group; + Group group; class Sensor { public: - Sensor(const Sensor&) = default; - Sensor& operator=(const Sensor&) = default; - Sensor(Sensor&&) = default; - Sensor& operator=(Sensor&&) = default; - - explicit Sensor(const Group<>& group) : - Samples( group ) - { } - - EventSource Samples; + EventSource samples = EventSource::Create(group); }; void Run() { cout << "Example 1 - Asynchronous transactions" << endl; - Sensor mySensor( group ); + Sensor mySensor; - Observer<> obs( - [&] (EventRange<> in) + auto obs = Observer::Create([&] (const auto& events) { - for (auto t : in) - cout << v << endl; - }, - mySensor.Samples); + for (auto t : events) + cout << t << endl; + }, mySensor.samples); - TransactionStatus status; + SyncPoint sp; - AsyncTransaction(status, [&] { - mySensor.Samples << 30 << 31 << 31 << 32; - }); + group.EnqueueTransaction([&] + { + mySensor.samples << 30 << 31 << 31 << 32; + }, sp); - AsyncTransaction(status, [&] { - mySensor.Samples << 40 << 41 << 51 << 62; - }); + group.EnqueueTransaction([&] + { + mySensor.samples << 40 << 41 << 51 << 62; + }, sp); // Waits until both transactions are completed. // This does not mean that both transactions are interleaved. - status.Wait(); + sp.Wait(); cout << endl; } @@ -78,17 +68,15 @@ namespace example2 using namespace react; using namespace std; - REACTIVE_DOMAIN(D, sequential_concurrent) + Group group; class Sensor { public: - USING_REACTIVE_DOMAIN(D) - - EventSourceT Samples = MakeEventSource(); + EventSource samples = EventSource::Create(group); }; - const int K = 100000; + const int K = 10000; namespace v1 { @@ -99,11 +87,13 @@ namespace example2 Sensor mySensor; int sum = 0; - Observe(mySensor.Samples, [&] (int v) { - sum += v; - }); + auto obs = Observer::Create([&] (const auto& events) + { + for (int e : events) + sum += e; + }, mySensor.samples); - TransactionStatus status; + SyncPoint sp; cout << "Executing " << K << " async transactions..."; @@ -111,12 +101,13 @@ namespace example2 for (int i=0; i < K; i++) { - AsyncTransaction(status, [&] { - mySensor.Samples << 3 << 4 << 2 << 1; - }); + group.EnqueueTransaction([&] + { + mySensor.samples << 3 << 4 << 2 << 1; + }, sp); } - status.Wait(); + sp.Wait(); double d = (tbb::tick_count::now() - t0).seconds(); @@ -138,11 +129,13 @@ namespace example2 Sensor mySensor; int sum = 0; - Observe(mySensor.Samples, [&] (int v) { - sum += v; - }); + auto obs = Observer::Create([&] (const auto& events) + { + for (int e : events) + sum += e; + }, mySensor.samples); - TransactionStatus status; + SyncPoint sp; cout << "Executing " << K << " async transactions..."; @@ -150,12 +143,13 @@ namespace example2 for (int i=0; i < K; i++) { - AsyncTransaction(allow_merging, status, [&] { - mySensor.Samples << 3 << 4 << 2 << 1; - }); + group.EnqueueTransaction([&] + { + mySensor.samples << 3 << 4 << 2 << 1; + }, sp, TransactionFlags::allow_merging); } - status.Wait(); + sp.Wait(); double d = (tbb::tick_count::now() - t0).seconds(); @@ -169,67 +163,6 @@ namespace example2 } } -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Example 3 - Continuations (1) -/////////////////////////////////////////////////////////////////////////////////////////////////// -namespace example3 -{ - using namespace react; - using namespace std; - - REACTIVE_DOMAIN(D, sequential_concurrent) - - class Widget - { - public: - USING_REACTIVE_DOMAIN(D) - - VarSignalT Label1 = MakeVar(string( "Change" )); - VarSignalT Label2 = MakeVar(string( "me!" )); - - EventSourceT<> Reset = MakeEventSource(); - - Widget() : - resetCont_ - ( - MakeContinuation( - Reset, - [this] (Token) { - Label1 <<= string( "Change" ); - Label2 <<= string( "me!" ); - }) - ) - {} - - private: - Continuation resetCont_; - }; - - void Run() - { - cout << "Example 3 - Continuations (1)" << endl; - - Widget myWidget; - - Observe(myWidget.Label1, [&] (const string& v) { - cout << "Label 1 changed to " << v << endl; - }); - - Observe(myWidget.Label2, [&] (const string& v) { - cout << "Label 2 changed to " << v << endl; - }); - - myWidget.Label1 <<= "Hello"; - myWidget.Label2 <<= "world"; - - cout << "Resetting..." << endl; - - myWidget.Reset(); - - cout << endl; - } -} - /////////////////////////////////////////////////////////////////////////////////////////////////// /// Run examples /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -240,7 +173,5 @@ int main() example2::v1::Run(); example2::v2::Run(); - example3::Run(); - return 0; } \ No newline at end of file From 6a936621281532a914c75b1886da54f56d1d9832 Mon Sep 17 00:00:00 2001 From: schlangster Date: Mon, 30 Oct 2017 22:03:57 +0100 Subject: [PATCH 61/75] Fixes + cleanup. --- include/react/detail/graph_impl.h | 26 ++++++++++++++++++++++ include/react/detail/observer_nodes.h | 2 +- include/react/detail/state_nodes.h | 12 ++++++---- include/react/group.h | 32 --------------------------- include/react/state.h | 19 ++++++++++++---- project/msvc/CppReact.sln | 11 --------- project/msvc/CppReact.vcxproj | 3 --- project/msvc/CppReact.vcxproj.filters | 12 ---------- tests/src/state_tests.cpp | 4 ++-- 9 files changed, 52 insertions(+), 69 deletions(-) diff --git a/include/react/detail/graph_impl.h b/include/react/detail/graph_impl.h index 42c04789..14391d14 100644 --- a/include/react/detail/graph_impl.h +++ b/include/react/detail/graph_impl.h @@ -216,6 +216,32 @@ void ReactGraph::EnqueueTransaction(F&& func, SyncPoint::Dependency dep, Transac transactionQueue_.Push(std::forward(func), std::move(dep), flags); } +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// GroupInternals +/////////////////////////////////////////////////////////////////////////////////////////////////// +class GroupInternals +{ +public: + GroupInternals() : + graphPtr_( std::make_shared() ) + { } + + GroupInternals(const GroupInternals&) = default; + GroupInternals& operator=(const GroupInternals&) = default; + + GroupInternals(GroupInternals&&) = default; + GroupInternals& operator=(GroupInternals&&) = default; + + auto GetGraphPtr() -> std::shared_ptr& + { return graphPtr_; } + + auto GetGraphPtr() const -> const std::shared_ptr& + { return graphPtr_; } + +private: + std::shared_ptr graphPtr_; +}; + /****************************************/ REACT_IMPL_END /***************************************/ #endif // REACT_DETAIL_PROPAGATION_H_INCLUDED \ No newline at end of file diff --git a/include/react/detail/observer_nodes.h b/include/react/detail/observer_nodes.h index 9634c89c..dd051384 100644 --- a/include/react/detail/observer_nodes.h +++ b/include/react/detail/observer_nodes.h @@ -150,7 +150,7 @@ class SyncedEventObserverNode : public ObserverNode return UpdateResult::unchanged; apply([this] (const auto& ... syncs) - { func_(EventRange( GetInternals(this->subject_).Events() ), GetInternals(syncs).Value() ...); }, syncHolder_); + { func_(GetInternals(this->subject_).Events(), GetInternals(syncs).Value() ...); }, syncHolder_); return UpdateResult::unchanged; } diff --git a/include/react/detail/state_nodes.h b/include/react/detail/state_nodes.h index ea78c20b..aa8c8b85 100644 --- a/include/react/detail/state_nodes.h +++ b/include/react/detail/state_nodes.h @@ -346,7 +346,8 @@ class ObjectStateNode : public StateNode> { public: ObjectStateNode(const Group& group, S&& obj, const std::initializer_list& memberIds) : - ObjectStateNode::StateNode( group, std::move(obj) ) + ObjectStateNode::StateNode( group, &object_ ), + object_( std::move(obj) ) { this->RegisterMe(); @@ -356,7 +357,7 @@ class ObjectStateNode : public StateNode> { REACT_EXPAND_PACK(memberIds_.push_back(GetInternals(members).GetNodeId())); REACT_EXPAND_PACK(this->AttachToMe(GetInternals(members).GetNodeId())); - }, this->Value().GetObject().GetReactiveMembers()); + }, object_.GetReactiveMembers()); } else { @@ -372,16 +373,18 @@ class ObjectStateNode : public StateNode> template ObjectStateNode(InPlaceTag, const Group& group, Us&& ... args) : - ObjectStateNode::StateNode( in_place, group, group, std::forward(args) ... ) + ObjectStateNode::StateNode( group, &object_ ), + object_( group, std::forward(args) ... ) { this->RegisterMe(); apply([this] (const auto& ... members) - { REACT_EXPAND_PACK(memberIds_.push_back(GetInternals(members).GetNodeId())); }, this->Value().GetObject().GetReactiveMembers()); + { REACT_EXPAND_PACK(memberIds_.push_back(GetInternals(members).GetNodeId())); }, object_.GetReactiveMembers()); } ~ObjectStateNode() { + // TODO: This must happen inside of the node for (NodeId id : memberIds_) this->DetachFromMe(id); @@ -394,6 +397,7 @@ class ObjectStateNode : public StateNode> } private: + S object_; std::vector memberIds_; }; diff --git a/include/react/group.h b/include/react/group.h index 45ec476a..d534d7e4 100644 --- a/include/react/group.h +++ b/include/react/group.h @@ -20,38 +20,6 @@ #include "react/detail/graph_interface.h" #include "react/detail/graph_impl.h" -/***************************************/ REACT_IMPL_BEGIN /**************************************/ - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// GroupInternals -/////////////////////////////////////////////////////////////////////////////////////////////////// -class GroupInternals -{ - using GraphType = REACT_IMPL::ReactGraph; - -public: - GroupInternals() : - graphPtr_( std::make_shared() ) - { } - - GroupInternals(const GroupInternals&) = default; - GroupInternals& operator=(const GroupInternals&) = default; - - GroupInternals(GroupInternals&&) = default; - GroupInternals& operator=(GroupInternals&&) = default; - - auto GetGraphPtr() -> std::shared_ptr& - { return graphPtr_; } - - auto GetGraphPtr() const -> const std::shared_ptr& - { return graphPtr_; } - -private: - std::shared_ptr graphPtr_; -}; - -/****************************************/ REACT_IMPL_END /***************************************/ - /*****************************************/ REACT_BEGIN /*****************************************/ /////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/include/react/state.h b/include/react/state.h index 6c93de6c..d8235d37 100644 --- a/include/react/state.h +++ b/include/react/state.h @@ -39,6 +39,11 @@ class State : protected REACT_IMPL::StateInternals static State Create(F&& func, const State& dep1, const State& ... deps) { return CreateFuncNode(dep1.GetGroup(), std::forward(func), dep1, deps ...); } + // Construct with constant value + template + static State Create(const Group& group, T&& init) + { return CreateFuncNode(group, [value = std::move(init)] { return value; }); } + State() = default; State(const State&) = default; @@ -292,8 +297,11 @@ class ObjectContext ObjectContext(ObjectContext&&) = default; ObjectContext& operator=(ObjectContext&&) = default; + S& GetObject() + { return *objectPtr_; } + const S& GetObject() const - { return object_; } + { return *objectPtr_; } template const U& Get(const State& member) const @@ -305,11 +313,11 @@ class ObjectContext private: template - explicit ObjectContext(Us&& ... args) : - object_( std::forward(args) ... ) + explicit ObjectContext(S* objectPtr) : + objectPtr_( objectPtr ) { } - S object_; + S* objectPtr_; template friend class impl::StateNode; @@ -345,6 +353,9 @@ class ObjectState : public State> ObjectState(ObjectState&&) = default; ObjectState& operator=(ObjectState&&) = default; + S* operator->() + { return &this->Value().GetObject(); } + protected: ObjectState(std::shared_ptr>>&& nodePtr) : ObjectState::State( std::move(nodePtr) ) diff --git a/project/msvc/CppReact.sln b/project/msvc/CppReact.sln index 5f987e52..6d60b1c9 100644 --- a/project/msvc/CppReact.sln +++ b/project/msvc/CppReact.sln @@ -17,8 +17,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "4_Benchmarks", "4_Benchmark EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "2_Tests", "2_Tests", "{3F97AA87-0A03-4428-94C1-C9B4007C2C80}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CppReactExample", "CppReactExample.vcxproj", "{CC0CD982-AE7D-4797-A122-58E6BBE70DDB}" -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Example_BasicAlgorithms", "Example_BasicAlgorithms.vcxproj", "{617019A2-97BE-4A60-8EC4-3547D8C54533}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Example_BasicComposition", "Example_BasicComposition.vcxproj", "{D7B70D3B-F14D-4A85-B164-EAB88C358E85}" @@ -67,14 +65,6 @@ Global {52A9EC67-C6A7-453B-AD65-F027CA07AF44}.Release|Win32.Build.0 = Release|Win32 {52A9EC67-C6A7-453B-AD65-F027CA07AF44}.Release|x64.ActiveCfg = Release|x64 {52A9EC67-C6A7-453B-AD65-F027CA07AF44}.Release|x64.Build.0 = Release|x64 - {CC0CD982-AE7D-4797-A122-58E6BBE70DDB}.Debug|Win32.ActiveCfg = Debug|Win32 - {CC0CD982-AE7D-4797-A122-58E6BBE70DDB}.Debug|Win32.Build.0 = Debug|Win32 - {CC0CD982-AE7D-4797-A122-58E6BBE70DDB}.Debug|x64.ActiveCfg = Debug|x64 - {CC0CD982-AE7D-4797-A122-58E6BBE70DDB}.Debug|x64.Build.0 = Debug|x64 - {CC0CD982-AE7D-4797-A122-58E6BBE70DDB}.Release|Win32.ActiveCfg = Release|Win32 - {CC0CD982-AE7D-4797-A122-58E6BBE70DDB}.Release|Win32.Build.0 = Release|Win32 - {CC0CD982-AE7D-4797-A122-58E6BBE70DDB}.Release|x64.ActiveCfg = Release|x64 - {CC0CD982-AE7D-4797-A122-58E6BBE70DDB}.Release|x64.Build.0 = Release|x64 {617019A2-97BE-4A60-8EC4-3547D8C54533}.Debug|Win32.ActiveCfg = Debug|Win32 {617019A2-97BE-4A60-8EC4-3547D8C54533}.Debug|Win32.Build.0 = Debug|Win32 {617019A2-97BE-4A60-8EC4-3547D8C54533}.Debug|x64.ActiveCfg = Debug|x64 @@ -151,7 +141,6 @@ Global {5E56AAB9-4E33-4B9E-A315-E85CEDB75CF1} = {91AFD614-F7E6-48CE-9808-642EAF476B66} {F9115FB9-61DD-4B3C-BCE8-7D26372B05F7} = {D6F88FF5-E55C-4E65-ABBB-B4298AB84D40} {52A9EC67-C6A7-453B-AD65-F027CA07AF44} = {3F97AA87-0A03-4428-94C1-C9B4007C2C80} - {CC0CD982-AE7D-4797-A122-58E6BBE70DDB} = {518ACABC-E4A7-4E2D-9A04-FFA669A30DBF} {617019A2-97BE-4A60-8EC4-3547D8C54533} = {518ACABC-E4A7-4E2D-9A04-FFA669A30DBF} {D7B70D3B-F14D-4A85-B164-EAB88C358E85} = {518ACABC-E4A7-4E2D-9A04-FFA669A30DBF} {BD777649-97F1-4810-BF21-CB27F7672BF4} = {518ACABC-E4A7-4E2D-9A04-FFA669A30DBF} diff --git a/project/msvc/CppReact.vcxproj b/project/msvc/CppReact.vcxproj index 088c482f..47748a0d 100644 --- a/project/msvc/CppReact.vcxproj +++ b/project/msvc/CppReact.vcxproj @@ -177,9 +177,6 @@ - - - diff --git a/project/msvc/CppReact.vcxproj.filters b/project/msvc/CppReact.vcxproj.filters index 040e8acc..5652b8e2 100644 --- a/project/msvc/CppReact.vcxproj.filters +++ b/project/msvc/CppReact.vcxproj.filters @@ -19,9 +19,6 @@ {11a75126-8bfd-4693-be4b-4e06ab73450c} - - {3f444875-ab1a-4bbd-99eb-7018c930098a} - {45678bfc-0ce5-4e47-a365-54a72d8ecb6d} @@ -83,15 +80,6 @@ - - Source Files\engine - - - Source Files\engine - - - Source Files\engine - Source Files\detail diff --git a/tests/src/state_tests.cpp b/tests/src/state_tests.cpp index 10e41205..ab9d70b8 100644 --- a/tests/src/state_tests.cpp +++ b/tests/src/state_tests.cpp @@ -475,6 +475,6 @@ TEST(StateTest, Object) int height = ctx.Get(widget.height); }, st1); - w1.color.Set(10); - w2.color.Set(20); + st1->color.Set(10); + st2->color.Set(20); } \ No newline at end of file From 40ea6e424d2fcd37abb4946a015e79de9a6ebf2a Mon Sep 17 00:00:00 2001 From: schlangster Date: Mon, 30 Oct 2017 22:06:00 +0100 Subject: [PATCH 62/75] Removed react player. No longer supported with new codebase. --- tools/ReactPlayer/ReactPlayer.swf | Bin 13905 -> 0 bytes tools/ReactPlayer/readme.txt | 8 -------- 2 files changed, 8 deletions(-) delete mode 100644 tools/ReactPlayer/ReactPlayer.swf delete mode 100644 tools/ReactPlayer/readme.txt diff --git a/tools/ReactPlayer/ReactPlayer.swf b/tools/ReactPlayer/ReactPlayer.swf deleted file mode 100644 index ee457a7c92999db5bab5c1804898901227834e32..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13905 zcmZv>18`3u}gq8#% zeYs9gMF4iFgtn~$VkC(>m+((%*#-nvEL7H|W8$!#MFLUf#-JPi-jBcw*b9ZJ;x2Pg zvA3C*5rZP1fV{gU0#pHy#nzKSm!>)x&jrFS_YL>Uwxe9{%dhpfTte(e$&lKQgFTZv z`No5v@Fd;YW!$05xR1zO_f4*?$T5&X2~b|E8r?#;1opqnc|5L-9{OAt3a+K(H#Xe2 z^i_2YRSgZr@zoRl8qK@^ru|V)ZSMjQ&BDcji;I<%1c-16y+HxcXKW7+GM53Sdtu8) z#j8iih!qQfg1SsV_f2N|=_+n2Kn@XPynu}u`UWTvHf3{e;{)p+@pC_`ez@Fpu+)kX zqlPy$vXq3K$c_~KYxS_D;AZ0M=C6!dgA7ucx|ggv+~EON~+X3okeWHd^~yuNq; zR#fclu5eRT|2X_?@4(}HLy4EJq zJ(V(Q^|`rgnzzeZF_Q$p9?J(>j$-c>V=Fm)t;pF?2~~b|iCU8j2o%eD+y|Uq!GsUz zkF_%4D`)uYw&ez7B*+d}GNU~}hR;_wOUUR8@SfUhZLN0tImIqld7GaBNHtHt&vHFeTf zS`+s_p3+SfP^Gh6VmPlk+QlnB`a|I@#OM$sId6J*natj*m5kinG=4I9c?4b!5FK24 zi~6ilRrq1O7j4%JM!FTCp2)cm*an>IX<;Ucq8agbJF%!;|5|Aa`&@8l6>+jKMeU? zzg^fAVjJ7Sy4|$*+w7c6VwyV>Pq=q|*uegTxnH@*D2!8tAU(x5qxPycU9JMqgG%>8 z_0Pu5eh_XxW%GQFHGnq=Ma6yX3Vr?6J6T$AHDo>tfA6!W36@qQF~5U`At1e9E1Jy0 zw%sL}dFKAuGDj!!y`QO?V7j*Fv=|_|dRb$_d>`m)iaT=e$f=3>m{|H~@!DM3|5AF% zRVwXy9J4%_|FXmAnu?syabNfv6XO3W16sR9xb~pHXP5OzWSouht`wL?#I(fUn%p~voH=N+CbM_aIrt+hOxs7vR^S>76=;=D2tVb?Tn?4El*a zb%px9VGO&Q)2>hO-h^Svd;*x?l7d63Go(X$F16?u{oWb+PyG1;ucL&+>oxScGofA3 z{X9ytuSfr2=2ww*x`9Hk4<9tPgL{iYdR~eR)szjq1H560h;4a%`umhx&>OLh&>6tpvbZTfFuu9~G^yrY$d z?7~S0oLm8cE-YuYd2OP854W@62&|!8ZIA zjQ%G_WJ~h-w#jd&1V2k$Xr?1@!UVZL+BXEhBkj2(&^JUe{@pkKiVSw6S5S0GuIHKr zn`m^GY*aAhZ3x9h3AK_`LtI*YFjmC_*@4OU>0D4W6${KChBv%-YRA_E|5XSq!+75N z2kXG#922P+lanN|F&G*pb!S>Ug&c}S1NXNLBw`n z6C1LYf`@G>*bX$RAe;-e5EQa0WNpf{nUIV}%um6??RLNMzE#0PBVR&i2YsP`{$VY^ zbG*-W;=d`kRrCBeV?|y)Hc5O*0@4o%WA+R25Jj+!U7SI|J&(QBCD<%ML5b(P4D5g{ z(*1QDLx?Ha{5-K`hFtMgi-bq*VqYv^-hbhrx-+JrBl2tMKP-^~q8;@8;_?L&_HuK1n=k_LYgmi`OFbN?@V0K4`2?%5U4X&`LCL|lU%zXU&W z2Dv}u7kD=HEf10qx?Ak|4yVN<;W^KxQ|dO)Jo|J?k`VlWyPt{p9qpR0 zmx_Q%q%tjkL3a9xV)h84pDD->&13L}pdUS?YR6sp3#rNxjW;_4iK<{g`q<(Bh0&7u zTNJtiipSlqU_01>Oz8iFllPawB5!!)Tz6*>p>K9RP+l|ibD5V0UZJGMBlbwX{~J=q z>xJrp=8?&Kw}|=&nfl$e|J%^#x4LK{xA*BAtfAZ>%Ch{wG?q?qnc4q4B$dx~d54tt zgYpQ9FZl@FTgWPd1y?)OjQHdyIeLJbF@!iU6P-N6JRX1M{SR^L1?kxp)M+4MP?JCJ z4?Cfl)VKtj@x}hE82mrxhRE?9M(5){&FvZ0=^a)3#Pd%j`4KzG(PzaT_RowZqn0J9 zJM@rsC<8#nQv4~$@}ukWyX&+e^oMI<&%rZG=oI=Uc`jG{72e1bq64eo$uq3Y1Nz`6 zgxe?V!9(YseDd-Cv=N@*+uXp1N#RwT`FR|zD+Kav5&0aERW>Pas6}pY>+C>|$#{;> z@tf4WWsoM!7IDrNDZwQ1yXv;*ws$Xl?^9q6-)7i;3(1SElpkK=)<0-`)G&QVf6osu zFeN(m|G`ylDL#0h1<3_{aZYIN+_W>UmjYl4c+7(+P*!lnexDtd8%>3OM4d*2?gTG{ z>^lj_yPH1ZzvubiVI0;clGO#l{3>6pI+p|35{|#I6y#@6N zRs$p!NuG3qp#(g;B0qX z;}u}-e~8)Ud0WkDAHCB_;&J8r6gnYsJ!ntb%G!LEF~~>Xb3cQ?b;7d%OGKK%DyNj4sUS5Jf$;bP2kyLh2E*?_%=qCQmFremZAw!LlZF(T z2$t3_FFk379^4(3Cz*PQ*m@|m#draDm>SeC z+`;NV-wLI6+T@Z*@-)=j*9N#(%>rokzA%pI9w-j2U=7XS`lWn$XqHca$hZw~QX#vX$wC!~>LY@X6S3Omp^_s6AbhTVNQ!YE3@mn-~ zH?AUmzt-S5cI|cDwt?t^O~wk*MYRL8LLYxWq`~{GzK>pS#!2iBr`nAt^$9n92D?Iu zr$jo;(5qpDS4#jKOO6>d6d5VP39k%v&7TM7`o{GgFHpW0%b^*}TlnVNU5dP#`%nmd z#8e^V7uRI6V_>+x>;5YMVLo(vnau!oJE9qo9QYE=&dX6~!O;&ELyf)XG_4s> zM!4hJ8?(I*Ve`!l-hr+bayfFDGh_|*QnXdC4Z3TO@OV08mZPsf8Wh5h%Y}{wE*oIh z>m<4uQ-_r7C2Dsx@%zJkxflnRbAWYXy7u1_Fks#oZhpLiAdpc;u>4)-KlRtpVMb~p zuE83y4-CPYH-aZ`jQ3qdxio)mA`B7O{;RBG{Gt*48}!41yA%JO*GOQeDdQnxHKVkj+rqSvsb|bW@z_eOg{3ZrHQG+sB4*oC%kt5$AZ4`_fmrRnb)oK1 zhGYeTLe?c$l?&Y(^N^yib3!OW^!TEiLg+#040)zp#GRYG<-^%1hs4b@`T<$4`{lA{OW>nCtHtMJ@3<+0e`#i z6%?R$MYdTBzJ2V~5TLe4Cifuj3tktnY%v%wGtioa&+?ez>Y5&f&oCId7cIs9n2A~( zYF+MHzQ_b(iQ7H;vLK=R&0tY>n)?s;C9{`|_#W)J7;)|#;8~*>$a>s)C3HlP`|vD% zx3Hf}n=7T>MkDJ1J|AtVnSZJJR(NE8^ftJis2flWE;_a_G4rCWYX}xY6p_{y62kPbruiq@Ht8oJB&a@{lY4`w{c zGkvzb)!Tv`=A1cdzjMny0}fcA!&emP2US{%(|)1TFr0%ow}7p|a81=?d%mS8^!u$L z^;6k-!h~L<5q1o19+Z8VQN5*HbO>KTf7$g%v7OsL8k+gv&19Y1yM4H!@B@S~|Ano@ zBZCQ#-{X!Km|@{KVv+ ze*1F$pIKWYWt3x79Afu`AJxBhy&zm3wS>H51QyR~8vgJ)*g`MB9xVju;YuZS<=47< zF2peJfX5m;A}_#uN44oqkT=9!AIm@DH-wlcmt@dyQ`lq~8{WR2@xeZ=Ef@JbCvD_6 z7_Ru6GVPxOR*{9jFdgbTGMwlg+58(UOLV%^YHdriu9rcAO0Oa-;Op?OzA#s0dakCp z{6_&3h3II!BnAJw>5ShFg zGasx%-jCu>ZWy(HZ*FNITHZ;nk(Ill|9OO@{BG80&(zf3p?M}xs8H1}uv;a1@9b6t z#Qbh&#KxQ@w`3_q5NVHVTD@8FOdG4oG1;S&q6>dCwQZL0*q zECDIiVjLm~lffpOEq?iJIGm-TiFrp}QVRl>Pl~Bo4ki`0kCj9#EJ4v5X|FMy0X@h} zbY3A0cI6*Q2{9I8lz~D&P!}GM)GPU~2%J%lvw@0{j9b^JPIx~gPln4~eB2syhwmhn z%Hou|@X7bv;gfs>Re8Ofk^6m02TS1Lb6*CMn@0#Jfj*-y&q>S$W0My0*cLvdkt{qi z6bw$1Gh~!fNdzH!o3P0)V0+^b`-;M!5IPSKO_3s^B9A5rU;`mcYh@(iQ&p{T_`+A* z0SS-aZp}uC`~9ZXLnKj=&^~=A#YWutgd6VIpQpYvfiZor2`U@$4LBdRFcDpcKd0Qs zM=n%APNWo^h7R--ZDt4u??suM8-`_?6bqQk&jUArFaR@vETct2Rg9>0JEVGw0 zt0;OTeasJ=L!}%Xmk3f5Rd}P8#*=)e?Pp*&xRv9L$#B7CJ7G7U1&$ZbS-#9^0p(1Q za)uFDV|ZL}ImXJdI?7n=Sry?=`dOz$4tYlSp)-z%@9=--29G<(dm{b+$Ry9plDh0a zr^re@MEQC|#0$`t8AL`<@88(Ap_41b-{J0NYNiwYLqDBRi=M>i=f%gdv5oJdEW5B- zW(@{Md{D{m#EaWQ)Y9Tl(T3k;r+3g!pZ)`W+%Xln>lL#2L)00Irh3A%GKm~gjC4lU z9nikwhQFZ@lI(l+L_Yds?hUI)<7u+k=?%3y{>Qmr%!+qFH|zYB>x$lWOQ|y^f9#Ot zbx`}e!I92)ypLDt(5OS;a9bTq^;s|NDDw|K^0bu)3qz2n5Q(L)_WmIU8`%}Z=RW$T zuHNwGu9!@GyoFV19{4SxXoQJ--J0Uvxr&q)9IPyfarqmw^nZ|aKRfkNfYVU|CE=IT zDi?LU0$-duc#rnXz2XDVq+{<{WU6elaiy^CQJlp^ z2>eQ71}qO|B*SeQEboNzBOstQW-Q)e% z)f&P`x9E!RJ(OPJyqF~p$E(Oi#)izhc)N5?EV-1styFaK*B7k_JFqY6j!?3f2_iC~-4I6J!%}Lj10tVd zjb9@HX~=XD0+U(#H}h%{Vl{dcnQ<<3Wv9Gf7psav*lVWz2+N=s>Y zi93S_%5~M+<<>`{{lxq;R_Mkrq&-Bb-2m)d&TqJiscv`EaoIfej249HvXZY(TgS$78?c#)PGwL7GB@mB`FQT3axGlId)pp zy7K-l-}$Ctw{);XQ0D()sBcfe?WlHUDfMuyq51(hlfeKHk;SdQCZRlCL_d&RhlpJ;^T#=WhIc(N(1JFmY1*~E-sR^HkZm?IFX`#Vh zEJiKZ^FBbw7HH9+eO2mIKQMNIH`FUd%zg|HlcVkd-II?b4q~`7NNKL~^MA4=uYjW2 z)3*{H@-ewYLgiRR#m$VkKA5(Qupmc;QyJaZGZBkvzC}PUIgyO`j;md$pRKeV*@F-k z)Zy}-%*%*6|Fyqk+Iu9?u7x-&PGSgKv`7S1DVS{LgB0cVajWiUFKsa`s7 zY154{#DuUv{^?LwtM(ss%V4E87{h{Mtlb8=ITE ztMj5AH)uJ(oeLv~k3fJhdunMjj(y*u8JW`0kDmd>pjAo7jgL0b@tf9bpx`Dpz@D76 z^ql=GnR%7JtAbBR}}N+{3pg64Cw{BkEN?*stZ?Rr)JgcbXb)eV3pg~UW>)Q9!8 zG@CTVoMUF_^#V%*2_plD)%XoTfyE3xRw7uIgmDS%N)1lPg2s*MpkTQG4;AYXQ_uoC z>u}N|G}qC9eh&lfZ$H05%{b2*^SpqDbp17tuh%T&a;w(3ErtAUKN)=8rY^&*FL;8b z)_YOT=`@PmFXy*bxD*%GfFcK4&DPuEVjpexaBF3vDEebI`h5pXui|^rICENBZ$U29 zA;uw;2?II&VgnKuJeJy&d3 zHv{byV{ov@E9YCqx96F2Q$<0Ox)C;v)^X11E+st>nCkSQN3%3kQpHswx09@me~|dP z_K<)+qzL#r9KKqu1u5x5s98k?$k2n)CNYAI%SNtLabY`G3~Whx+D&o<@bm>_TYA6> z?<~KQ!=8Tk11OIS#c?jl?7C&Tf?06~F_iiUsQP;kisA5)Qx+BlMpzc548f>|{e-w{ zoUy@0lFv*!AxGkpEb1=!IMj+E#n~g{fP-EG?g@&tHU1`R%xAvQA{$SB%ooBTOR9?& zc^rmk!nH{J;deUw@!k9v3#kx=*q_37gqC0m&*)X6N^;rn=*N^nk%XqOP~s z+zj1?ysG%>8n`{Pe7H&z@FKn&LuWKPe_g^Q_#2hb7iIvR*Vd9}CkIXWhD!LN#?0>V z#B(Zg&58nT-2r&pn7CNR-~jX;X4pA36!5)vMiD<$jb?dMV8qa5FLg)yh?TxyTjA+! zE@H!MAtvrE+)@O4YLu41Ys^D|nS8`hVU}hTqTN|@U(H=3v~TeD48dmReavEAT~Vj% zy7X2Gqrp!6Xx;Bf8AOc>x3zK6JMNMIJ5DN%;8JncIknO-^-+wd3lgBJwx1M6U01Z; z;G5Pd@lpoW+jzjl z1LuvRQ+So;voTigbaxU3Fs{j_#pT+&lm$b)MEhneN0L|RyJZ_ALAs%uE)lVIb+%c* ztuP1-W)_&d+@lCXt|lH%asN60m;%~t9Xg{OGk0zBjB7iTaZC}>ca-i=$n zEL?8N=|po;r{Sa=)bOtdYMxn}*#6bFuCg~}wW;QvDoarIFJ>-{;|w(!_Ei}nxZ*9l zmf1Nw=|Lp4dF0obSseRJquS-x!xQL~ce9gY+Mqr#T8NfqcV_Oh3&yap)$C z`EUDx5r{X@nznr%#z)oe%ekYR00Rb;vNfjvCqBe>4Y#?a63-Sbt2uX&)azcJOh=W# z!!v3Bc9RoFceuiXNm;3bhQ;~`_rOP$9CW>&4x`@<_QLm;D8Xxwonazo;&;OKqqB4| zYkali{%|(#uzsyc(mK~W#sVa)i_oJP$N&r!KD!$+ET8Vmz0ku+3lW)5Z)AzAbP7!n z()Qyrb0JE+JZtpoo@FtMlkR zWj#JpIX*J>yCaR>6+2sUBZEiu&XUXBvV=Mc+|1F^>~GT~GSX73a!|jRwZJ={mUR-v z1lb|`PPZ6fwS z5EUWvYqEns8;m2<-^@L-3aPI{SvufE9&tw^^6dDh6`&pTPG1LQ*d zWdi)8$com;Ux7s3g#tbaM1*sM-Gj)`P2qo@jrF{rS%splkmK$K@*l5>UUvL0c95S7 z485Nf-=_x*bdfRqgY?I%Yrf?{2tx8ByaTrVp*~Tsf!jpjao>92_~Cp?mD#kOrTnTc zOW+&EnEJKexvS7$ml|mmu?FB#0dh6A1GG8|4kEuEGL?MKhnt_ zB_egg9Lr0br%Mj4RQqf_P;8S^qCv0f#bA1pYL@}2`t5jO;gE_qzyD1UdbuqlemE*0 zK{1IuQ2g~ylOkmIqRNP_Mq1X!_C8D?3&V0l@h(OTcyB$3Qx>fq&)AtKVDr%=26RvW zdd8=j*zWx!5x&L<*cx?N8^;hXSOFd5({_KaIVnrN`2#8z;Je`A4n?-(x=IrH*_Zr{6$ja2|MI}tu6ksElV%Z z?YN5+PB~0w@=fynH6x-^NIb5{2S{7-%9jCeCx^o;CKK~}CNMC#=#$#;bED?A3B9f- zgQ)<<^RF^~ykc;HB|AGM>Fut`xr#jXGM)xm@>uJ=WPir8L>*U*xI~febLJ6Vx`TjKs4GfR9ZRb>7FP# zvaa|{I{vEIP^8~=DzZn-hj*ME*{(J9|F$*t{Q!+P<%T`4`5JEtnu03-dY(ecVMpeq z?YA;G1W2$=@ZuLs2kyZ%_NH}{Ck|+UvCvRfwL{ULg>*^^7k~qV+hemwYc1^7mC~fY3jCYgH*6QjvX{4kwk*rtR z%1nQ{DU#v4%4qv^dMn3(QSEY=>~z) zxVtldCYKScz|ULXwB?jMv>&!Wr!VR9OVJp0#$qNqoRkBHtgZ^Px&ikd+=$mfb=xy- zBr?qr6pET_Vbjser6&isj2r_t(~>?do_}{KfZf|QS-ndZ&un`t$50Z-p$m#?X7cKE z*}}SVskE#}iYBAU$~Q^B=)z1i!+g9dKuOt{g_N=pLZwEHX4>s()$x6_!`UlL$zovEfj=ZQ%$#C z11A+4**WKv<$aK(0AbraM@(tPD$_~wA$6*a>d1vQwYVr6%!W*}OIAHc?~s){8rdOh z0=T+IqB9&@X4X}T!$)bm?1A?&gu6cv>+;l-U(?Pj zKIC+Z)W4hPF%C!Tz3;mQHzYOgEHv3PqY#KR6u9@~Q;b&+xeq2&sKyQ6)G!wmZMe13 z;5myI@20R`8q^&}o6NEUN1H|uCEDbr4yNqA9gXTv95`spmDWz$ z%c61?fV0{cE*#oKS#?uZ(pH;TppwC6qsU5*$+xQ3Rig>3GldCA#JvnxuPg)83&P2+ zb;=wpg8FtK{L7PxRZ}n4H$F^&s7ddSh`(y{i+n8ZID;3yb(|-sCjNAyeBAp%XSrH< z0=R8ie-Gax1mtJ?fmJzF9N6H}Rq1YNnz5g5*?3sicE6#D$QVba>$MA)8$a8Ajo=te zd|*4zrcvgl@w)c33sT!ATA(?lftorVQXfyJp|BgcSL@Q$ z`>g6@_p5U@ILyhbjTx0<;09B>v*QZMg*$w76k|?Ykcks%(#Kf4qg8A){mB>I>mqb< zu;YdgxzsAdN~ehSFzK1{F;<~E;cHj$6iM1uNuEbdoewvm94oH@$1E zpK{2$NV=q7vPvKY(PH(*(zs6xQYd(zZJ!DQ+)$S6?zUgsQ(am#zVIJ-?lA6X=ns3tTIiGr@uK+LurEdn6S(oCJ5e1?L*JPaV_ z1+vO{D`rS2)#%4k9QrMDUUC(TIF@MM=j$*j8h!5VF)Z8%=X~CS&S<<0p`oS|59Cw> zmOL&VZ35N>G?o<5n`Q}>rp2Zu@KOQPHYFP}IZk>{E$;4H_Cr~N%Z+IG%tkI&hN((y z%HLbIG7_snRr@lsn?dfA)6U4t+Di@T_2vz%+!IMQ%UiP-aUkUvi-F@$+%y2TRe{Y? zu$I6Y5L}5V8ZiLfv?}2dXfqv)Sq5_eBE?#?H0b!r&d)fP)T3i zGMFd5xx2u;Ma(2~UZ$gq6H^@D;Q7tl#2LDC@bQ~_8)PbuU#%_OhAdYgSr6gFE@7^0{VNnYvBVAy?m1Vd zvH8heg3U6MB@>ki@OoJV4pzVHmO|fa#Wlv{j4ITV|V^Cpyf{0Uv}>Z zrUo*KBOa2hJ^rPf&&9V=14)pFBWC>W4vdaWp(E_@(Q@_dJ%d&^Q>(%q)149{oN=2x zQdv@jJM-tsvt@;SdUd5?4`k2zGyExP)O#|AOlywn@( z?0@av4>J(RzQW0K21S(QDojYEp1jle@=mc0FLz92++y;B0x}$ben3d3<*k&*Ekz+} z14R`#ez$F455Mg+$V12x%5q$x!f9^PE{O6}>&1{5PBJcj_ho^)H+v1ZjK#aUL(#{I zQV`rM8y7-D5A!xBpv?UrH)bN?qz7Y&i*qzO(rXBoQ&eIkzqBZGBjfIM1FWV zWuFse+k&(`e>`v)d$Blm6E`SPeF zm8e9OD8y4e1>O^3UDoiVNubkg%J@mKu2->&F7439AUh-FH6BD>6kX?pj>nLneRTY& zMWZM`m3=3pEPF(AVPYkD_~obrUMf-q4?RyBfr_1Vc(Uh8flW1Dxt2-W=n?gB8C!%S z1GMLgBg3EUr3&(iWapa3=DY)mJy3EYTD2{TV{G%!cCR|}I)E>HsJ^jn`WPs5LJj|~ zwYR}UBgx+!6p)j~X*f$g-;)lLyPG z6kF9gCUl(^W**zAGLdoLVVggzq?q;1IL`JZ8=l8u*C!(`8~89SfU71y#$hXsYEo`&sP|@jP&%R-AHCpnSgJmW*>RZQiZQI$;6-^; z*|s1$^+a<4KuSf*+nWi;_7D0lcaqXJdxU#JXFrv0A*h&8WYq0~RH?LsD7sy<9bcrV1Nx(ht{i?RZBGjz!&@ zp>L^fv|Rdgi{9tvW6OySLX@2G+y#*vbl?gdnrq_+TKd$Sns%p>M83sB`#?I5@ybJ% zLj}Tk8Pi=okbJgTI=5yP)npxD;aNwt>82@UrAmX3iszkqAy?2dmSDDQqSc-bK@lQ+ zoatyxkpbZa?7KRqvSE5DW1qi{mr4{Xn%^UvY`Hj0ne#dgK@q8{x6KV%s1rH(**)pb zkHe(=kdF=)B8rW`F;0u6ryZI@N2(OVn}(=l%zhl)cd)+}bVzU)%zmLW#d@nIBgtxs z*{iU)EkqxdqkX!LNl`2@1W_=?lk8hFlic;fTilMHl_tUBnSQe=#q{OAG0u&=IC*H+ z-Wd{Wxfr6t_f(1c9DA*JTA;fZf}yLwHEj$hT7q8?nL)e*0KMQqx78aHM)myR zX27iwKW(g2Fe7)n@|1OU2>7vaVWp!&lZtaEg_vq%?NJ_fWkM|&C2}EHDcxi9v6(zh zDQ>N}xPntNK)30klle}rAt%ARg<1#vU>cZ3VG~%KONSh88kF-yN~#O%(S(eeTK1$% zq|lzzhd13SC^SoUy-A3(wN&7z>r-8|O-T<|n6zE=O)I5`FkMl%UYg9}A4V8P)(f#Y z>qoZO`ZAI2q%XcZ+WlzmTrP_$y&B18nri$cgq}r0!pd-e23CvvmiC)nZ}>$e_Y2A* zxjC=z3hrSlJL_XV{DtKzXa0zlI^SsGgI&8x_R}6LFV6f^xvT#=Goq+uA&bU3XV{t9 zviMxBg(i|`aK>E^(1pgeFhsINO(gXWG&vJrE9lS8$k0@uInGH<56)(-TC*-POtwTa z?1UQ5OL>LwJIdt@KOmpi+Wcd;lxhbc8x|pq+gv1|D`#CtToC*wz6I)o@csFDxc?08D#ZyL{fBi2wdbYoSrCxGV99c zecg|`BGIEqxJrpAWBcj|Av8#Ni<-svac=awEK5VI25E zww+YEMzY{$N4vzJGdY59b};@vxJ~%NwOUS-YDKaU$AxN~+kn;D z%Vhm_at9qgAVZ4aC+#rJ31ehEL573wx0?V0V~_@Wugz_*m7ujbM7K_keO zKewUabw(;1Ufu2$6cB948{FVN176h%m}y5|aZVG`kxiXduyt6YorAaTkH8ZZBQ)#JceB50b+tao&IY1cp6l4Gvp&F*pOIc{ RqIW2BVhCTz(3;UA{|CuOHLm~w diff --git a/tools/ReactPlayer/readme.txt b/tools/ReactPlayer/readme.txt deleted file mode 100644 index 6d22437d..00000000 --- a/tools/ReactPlayer/readme.txt +++ /dev/null @@ -1,8 +0,0 @@ -load LOGNAME : Loads event log from LOGNAME.txt. -play [PROFILE] : Starts event playback. Profiles: normal (default), verbose, fast, faster, forward -pause : Pauses event playback. -step : Steps to the next event. -reload : Reloads the current event log. -debugmode STATE : Enable/disable debug mode. States: 0, 1 -showthreads TURN : Show thread markers for given turn. -clearthreads : Clear thread markers. \ No newline at end of file From 928e8b9157c874347e92db92deb7a95d5a39209b Mon Sep 17 00:00:00 2001 From: schlangster Date: Mon, 30 Oct 2017 22:06:24 +0100 Subject: [PATCH 63/75] Removed test example. --- examples/src/Main.cpp | 488 ------------------------------------------ 1 file changed, 488 deletions(-) delete mode 100644 examples/src/Main.cpp diff --git a/examples/src/Main.cpp b/examples/src/Main.cpp deleted file mode 100644 index 3d3bb8e4..00000000 --- a/examples/src/Main.cpp +++ /dev/null @@ -1,488 +0,0 @@ - -// 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 "react/Signal.h" -#include "react/Event.h" -#include "react/Algorithm.h" -#include "react/Observer.h" - -#include "react/common/expected.h" - -using namespace react; - -template -class GridGraphGenerator -{ -public: - using SignalType = Signal; - - using Func1T = std::function; - using Func2T = std::function; - - using SignalVectType = std::vector; - - SignalVectType inputSignals; - SignalVectType outputSignals; - - Func1T function1; - Func2T function2; - - std::vector widths; - - void Generate(const Group& group) - { - SignalVectType buf1 = std::move(inputSignals); - SignalVectType buf2; - - SignalVectType* curBuf = &buf1; - SignalVectType* nextBuf = &buf2; - - size_t curWidth = buf1.size(); - - size_t nodeCount = 1; - nodeCount += curWidth; - - for (auto targetWidth : widths) - { - while (curWidth != targetWidth) - { - // Grow or shrink? - bool shouldGrow = targetWidth > curWidth; - - auto l = curBuf->begin(); - auto r = curBuf->begin(); - if (r != curBuf->end()) - ++r; - - if (shouldGrow) - { - auto s = SignalType{ group, function1, *l }; - nextBuf->push_back(std::move(s)); - } - - while (r != curBuf->end()) - { - auto s = SignalType{ group, function2, *l, *r }; - nextBuf->push_back(std::move(s)); - ++nodeCount; - ++l; ++r; - } - - if (shouldGrow) - { - auto s = SignalType{ group, function1, *l }; - nextBuf->push_back(std::move(s)); - ++nodeCount; - } - - curBuf->clear(); - - // Swap buffer pointers - SignalVectType* t = curBuf; - curBuf = nextBuf; - nextBuf = t; - - if (shouldGrow) - ++curWidth; - else - --curWidth; - } - } - - //printf ("NODE COUNT %d\n", nodeCount); - - outputSignals.clear(); - outputSignals.insert(outputSignals.begin(), curBuf->begin(), curBuf->end()); - } -}; - - -template -T Multiply(T a, T b) -{ - return a * b; -} - -template void PrintValue(T v) -{ - printf("Value: %d\n", v); -} - -template void PrintArea(T v) -{ - printf("Area: %d\n", v); -} - -template void PrintVolume(T v) -{ - printf("Volume: %d\n", v); -} - -template void PrintEvents(EventRange evts) -{ - printf("Processing events...\n"); - - for (const auto& e : evts) - printf(" Event: %d\n", e); -} - -template void PrintSyncedEvents(EventRange evts, int a, int b) -{ - printf("Processing events...\n"); - - for (const auto& e : evts) - printf(" Event: %d, %d, %d\n", e, a, b); -} - -template bool FilterFunc(T v) -{ - return v > 10; -} - -template T IterFunc1(EventRange evts, T v) -{ - return v + 1; -} - -template T IterFunc2(EventRange evts, T v, T a1, T a2) -{ - return v + 1; -} - -int main1() -{ - Group group; - - { - // Signals - VarSignal x{ group, 0 }; - VarSignal y{ group, 0 }; - VarSignal z{ group, 0 }; - - Signal area{ Multiply, x, y }; - Signal volume{ Multiply, area, z }; - - Observer areaObs{ PrintArea, area }; - Observer volumeObs{ PrintVolume, volume }; - - x.Set(2); // a: 0, v: 0 - y.Set(2); // a: 4, v: 0 - z.Set(2); // a: 4, v: 8 - - group.DoTransaction([&] - { - x.Set(100); - y <<= 3; - y <<= 4; - }); - - // a: 400, v: 800 - } - - { - // Events - EventSource button1{ group }; - EventSource button2{ group }; - - Event anyButton = Merge(button1, button2); - Event filtered = Filter(FilterFunc, anyButton); - - Observer eventObs{ PrintEvents, anyButton }; - - button1.Emit(1); - button2.Emit(2); - - group.DoTransaction([&] - { - for (int i=0; i<10; ++i) - button1.Emit(42); - }); - } - - { - // Dynamic signals - VarSignal s1{ group, 10 }; - VarSignal s2{ group, 22 }; - - SignalSlot slot{ s1 }; - - Observer areaObs{ PrintValue, slot }; - - s1.Set(42); - - slot.Set(s2); - - s2.Set(667); - } - - { - // Dynamic events - EventSource s1{ group }; - EventSource s2{ group }; - - EventSlot slot{ group }; - - Observer eventObs{ PrintEvents, slot }; - - slot.Add(s1); - slot.Add(s2); - - slot.Remove(s1); - slot.RemoveAll(); - } - - // Links - { - Group group1; - Group group2; - - VarSignal s1{ group1, 10 }; - VarSignal s2{ group2, 11 }; - - Signal v{ Multiply, s1, s2 }; - - Observer obs{ PrintValue, v }; - - s1.Set(555); - - std::this_thread::sleep_for(std::chrono::seconds(5)); - } - - { - Group group1; - Group group2; - - VarSignal s1{ group1, 10 }; - VarSignal s2{ group2, 11 }; - - EventSource e1{ group1 }; - EventSource e2{ group2 }; - - auto hold = Hold(group1, 0, e1); - - auto merged = Merge(group2, e1, e2); - - auto joined1 = Join(e1, e2); - auto joined2 = Join(group1, e1, e2); - - Observer eventObs1{ PrintEvents, merged }; - Observer eventObs2{ group2, PrintSyncedEvents, merged, s1, s2 }; - - e1.Emit(222); - - std::this_thread::sleep_for(std::chrono::seconds(5)); - } - - { - Group group1; - Group group2; - - VarSignal s1{ group1, 10 }; - VarSignal s2{ group2, 11 }; - - EventSource e1{ group1 }; - EventSource e2{ group2 }; - - auto hold1 = Hold(group1, 0, e1); - auto hold2 = Hold(0, e1); - - auto monitor1 = Monitor(group1, s1); - auto monitor2 = Monitor(s1); - - auto snapshot1 = Snapshot(group1, s1, e1); - auto snapshot2 = Snapshot(s1, e1); - - auto pulse1 = Pulse(group1, s1, e1); - auto pulse2 = Pulse(s1, e1); - - auto merged = Merge(group2, e1, e2); - - auto joined1 = Join(e1, e2); - auto joined2 = Join(group1, e1, e2); - - auto iter1 = Iterate(group, 0, IterFunc1, e1); - auto iter2 = Iterate(0, IterFunc1, e1); - - auto iter3 = Iterate(group, 0, IterFunc2, e1, s1, s2); - auto iter4 = Iterate(0, IterFunc2, e1, s1, s2); - - Observer eventObs{ PrintEvents, merged }; - Observer eventObs2{ group2, PrintSyncedEvents, merged, s1, s2 }; - - e1.Emit(222); - - std::this_thread::sleep_for(std::chrono::seconds(5)); - - GridGraphGenerator grid; - } - - return 0; -} - - -int main() -{ - Group group; - - Group extGroup; - - // Dynamic events - EventSource s1{ group }; - EventSource s2{ group }; - EventSource s3{ extGroup }; - //EventSource s4{ extGroup }; - - EventSlot slot{ group }; - - Observer eventObs{ PrintEvents, slot }; - //Observer extObs{ PrintEvents, link1 }; - - //slot.Add(s1); - //slot.Add(s2); - - group.DoTransaction([&] - { - s1.Emit(1); - s2.Emit(2); - - - slot.Add(s3); - slot.Add(s3); - slot.Add(s3); - slot.Add(s3); - }); - - s3.Emit(3); - - std::this_thread::sleep_for(std::chrono::seconds(5)); - - Expected x; - - return 0; -} - - - - - - - - -int main2() -{ - Group group; - - VarSignal in{ group, 1 }; - Signal in2 = in; - - GridGraphGenerator generator; - - generator.inputSignals.push_back(in2); - - generator.widths.push_back(100); - generator.widths.push_back(1); - - int updateCount = 0; - - generator.function1 = [&] (int a) { ++updateCount; return a; }; - generator.function2 = [&] (int a, int b) { ++updateCount; return a + b; }; - - generator.Generate(group); - - updateCount = 0; - - auto t0 = tbb::tick_count::now(); - for (int i = 0; i < 10000; i++) - in <<= 10 + i; - auto t1 = tbb::tick_count::now(); - - double d = (t1 - t0).seconds(); - printf("updateCount %d\n", updateCount); - printf("Time %g\n", d); - - return 0; -} - - - - - - - - - - - - - -/* - -int main7() -{ - Group group1; - Group group2; - Group group3; - - VarSignal x{ group1, 0 }; - VarSignal y{ group2, 0 }; - VarSignal z{ group3, 0 }; - - Signal area{ Multiply, x, y }; - Signal volume{ Multiply, area, z }; - - Observer obs{ PrintAreaAndVolume, area, volume }; - - Signal> volumeHistory = Iterate>( vector{ }, PushToVector, Monitor(volume)); - - x <<= 2; - y <<= 2; - z <<= 2; - - group.DoTransaction([&] - { - x <<= 100; - y <<= 200; - z <<= 300; - }); - - obs.Cancel(); - - x <<= 42; - - printf("History:\n"); - for (auto t : volumeHistory.Value()) - printf("%d ", t); - printf("\n"); - - return 0; -} - - -int main3() -{ - using namespace std; - using namespace react; - - Group group1; - Group group2; - - auto sig1 = VarSignal( 10, group1 ); - - auto link1 = SignalLink( sig1, group2 ); - auto link2 = SignalLink( sig1, group2 ); - - sig1.Set(10); - - return 0; -} - -*/ \ No newline at end of file From eae1a8c20d67faa6182d684fa3eedf01543c0c9c Mon Sep 17 00:00:00 2001 From: schlangster Date: Mon, 30 Oct 2017 22:17:26 +0100 Subject: [PATCH 64/75] Updated readme. --- README.md | 185 +++++++----------------------------------------------- 1 file changed, 24 insertions(+), 161 deletions(-) diff --git a/README.md b/README.md index 5c27b6bc..0654cddc 100644 --- a/README.md +++ b/README.md @@ -1,177 +1,40 @@ # ![C++React](http://schlangster.github.io/cpp.react//media/logo_banner3.png) -C++React is reactive programming library for C++11. +C++React is reactive programming library for C++14 that enables declarative definition of data dependencies between state and event flows. +Based on these definitions, propagation of changes is handled automatically. -Generally speaking, it provides abstractions to handle change propagation and data processing for a push-based event model. -A more practical description is that it enables coordinated, multi-layered - _and potentially parallel_ - execution of callbacks. -All this happens implicitly, based on declarative definitions, with guarantees regarding +Here's a simple example: -- _update minimality_ - nothing is re-calculated or processed unnecessarily; -- _glitch freedom_ - no transiently inconsistent data sets; -- _thread safety_ - no data races for parallel execution by avoiding side effects. - -The core abstractions of the library are - -- _signals_, reactive variables that are automatically re-calculated when their dependencies change, and -- _event streams_ as composable first class objects. - -Signals specifically deal with aspects of time-varying state, whereas event streams facilitate event processing in general. - -Additional features include - -- a publish/subscribe mechanism for callbacks with side effects; -- a set of operations and algorithms to combine signals and events; -- a domain model to encapsulate multiple reactive systems; -- transactions to group related events, supporting both synchronous and asynchrounous execution. - - -## Documentation - -[If you're interested in learning about C++React, have a look at its documentation.](http://schlangster.github.io/cpp.react/) - - -## Using the library - -This library is a work-in-progress. It should not be considered release quality yet and its API might still change. -It is, however, in a perfectly usable state and has already received a fair amount of testing and tuning. - -### Dependencies - -* [Intel TBB 4.2](https://www.threadingbuildingblocks.org/) (required) -* [Google test framework](https://code.google.com/p/googletest/) (optional, to compile the unit tests) -* [Boost 1.55.0 C++ Libraries](http://www.boost.org/) (optional, to include Reactor.h, which requires `boost::coroutine`) - -### Compiling - -C++React has been tested with the following compilers: - -* Visual Studio 2013.2 -* GCC 4.8.2 -* Clang 3.4 - -To build with Visual Studio, use the pre-made solution found in `project/msvc/`. - -To build with GCC or Clang, use [CMake](http://www.cmake.org/): -``` -mkdir build -cd build -cmake .. -make ``` - -For more details, refer to the [Build instructions](https://github.com/schlangster/cpp.react/wiki/Build-instructions). - - -## Features by example - -### Signals - -Signals are self-updating reactive variables. -They can be combined in expressions to create new signals, which are automatically re-calculated when their dependencies change. - -```C++ -using namespace std; using namespace react; -// Defines a reactive domain that uses single-threaded, sequential updating -REACTIVE_DOMAIN(D, sequential) +void AddNumbers(int a, int b) { return a + b; } -// Defines aliases for types of the given domain, -// e.g. using VarSignalT = VarSignal -USING_REACTIVE_DOMAIN(D) +// Two state variable objects. You can change their values manually. +auto a = StateVar::Create(0); +auto b = StateVar::Create(0); -// Two reactive variables that can be manipulated imperatively -// to input external changes -VarSignalT width = MakeVar(1); -VarSignalT height = MakeVar(2); +// Another state object. Its value is calculated automatically based on the given function and arguments. +// If the arguments change, the value is re-calculated. +auto sum = State::Create(AddNumbers, a, b); -// A signal that depends on width and height and multiplies their values -SignalT area = MakeSignal( - With(width, height), - [] (int w, int h) { - return w * h; - }); +// sum == 0 +a.Set(21); +// sum == 21 +b.Set(21); +// sum == 42 ``` -Signal values can be accessed imperatively: -```C++ -cout << "area: " << area.Value() << endl; // => area: 2 -// Width changed, so area is re-calculated automatically -width.Set(10); +The underlying system constructs a dependency graph to collect which values are affected by a change, and in which order they have to be re-calculated. +This guarantees several properties: +- _correctness_ - no updates are forgotten; +- _consistency_ - no value is updated before all its incoming dependencies have been updated; +- _efficiency_ - no value is re-calculated more than once per update cycle, and changes are only propagated along paths where a new value is different from the old one. -cout << "area: " << area.Value() << endl; // => area: 20 -``` - -Or, instead of using `Value()` to pull the new value, callback functions can be registered to receive notifications on a change: -```C++ -Observe(area, [] (int newValue) { - cout << "area changed: " << newValue << endl; -}); -``` - -Overloaded operators for signal types allow to omit `MakeSignal` for a more concise syntax: -```C++ -// Lift as reactive expression - equivalent to previous example -SignalT area = width * height; -``` - -### Event streams - -Unlike signals, event streams are not centered on changing state, but represent flows of discrete values. -They are first-class objects and can be merged, filtered, transformed or composed to more complex types: - -```C++ -using namespace std; -using namespace react; - -REACTIVE_DOMAIN(D, sequential) -USING_REACTIVE_DOMAIN(D) - -// Two event sources -EventSourceT leftClick = MakeEventSource(); -EventSourceT rightClick = MakeEventSource(); - -// Merge both event streams -EventsT anyClick = leftClick | rightClick; - -// React to events -Observe(anyClick, [] (Token) { - cout << "clicked!" << endl; -}); -``` -``` -leftClick.Emit(); // => clicked! -rightClick.Emit(); // => clicked! -``` - -### Parallelism and concurrency - -When enabling it through the concurrency policy, updates are automatically parallelized: - -```C++ -REACTIVE_DOMAIN(D, parallel) - -VarSignalT in = MakeVar(0); - -SignalT op1 = MakeSignal(in, - [] (int in) { - int result = doCostlyOperation1(in); - return result; - }); - -SignalT op2 = MakeSignal(in, - [] (int in) { - int result = doCostlyOperation2(in); - return result; - }); - -// op1 and op2 can be re-calculated in parallel -SignalT out = op1 + op2; -``` +The system also knows when it's safe to update values in parallel from multiple threads, and it can do live profiling to decide when that's worthwhile. -## Acknowledgements +## Development status -The API of C++React has been inspired by the following two research papers: +I'm currently in the process of rewriting the library more or less from scratch and many things are still broken or outdated. -* [Deprecating the Observer Pattern with Scala.React](http://infoscience.epfl.ch/record/176887/files/DeprecatingObservers2012.pdf) -* [REScala: Bridging Between Object-oriented and Functional Style in Reactive Applications](http://www.stg.tu-darmstadt.de/media/st/research/rescala_folder/REScala-Bridging-The-Gap-Between-Object-Oriented-And-Functional-Style-In-Reactive-Applications.pdf) +[The old, but stable and documented version is still available in this branch.](https://github.com/schlangster/cpp.react/tree/legacy1) \ No newline at end of file From 5467003302e656c8fd983e619ccfe02a96007ffb Mon Sep 17 00:00:00 2001 From: schlangster Date: Mon, 30 Oct 2017 22:18:58 +0100 Subject: [PATCH 65/75] Readme. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0654cddc..f38e6486 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # ![C++React](http://schlangster.github.io/cpp.react//media/logo_banner3.png) -C++React is reactive programming library for C++14 that enables declarative definition of data dependencies between state and event flows. +C++React is reactive programming library for C++14. It enables the declarative definition of data dependencies between state and event flows. Based on these definitions, propagation of changes is handled automatically. Here's a simple example: From 76be2a9438047148bcdd412eb7fde2148e3c57cf Mon Sep 17 00:00:00 2001 From: schlangster Date: Wed, 1 Nov 2017 01:29:13 +0100 Subject: [PATCH 66/75] Added Ref wrapper template. StateVars always contain elements by-value, but for State it might be convenient to use pointers/references, especially when dealing with class types. Use CreateRef for State -> State> binding. Semantically, it's the same as using State, but avoids the null check. The State> changes when the referenced state changes. --- include/react/api.h | 21 ++++++++++++++ include/react/detail/state_nodes.h | 44 ++++++++++++++++++++++++------ include/react/state.h | 19 +++++++++---- 3 files changed, 71 insertions(+), 13 deletions(-) diff --git a/include/react/api.h b/include/react/api.h index 95ce57f6..2223cae8 100644 --- a/include/react/api.h +++ b/include/react/api.h @@ -9,6 +9,7 @@ #pragma once +#include #include #include "react/detail/defs.h" @@ -93,6 +94,26 @@ using EventValueSink = std::back_insert_iterator>; // Observer class Observer; +// Ref +template +using Ref = std::reference_wrapper; + +template +bool HasChanged(const T& a, const T& b) + { return !(a == b); } + +template +bool HasChanged(const Ref& a, const Ref& b) + { return true; } + +template +void ListInsert(T& list, V&& value) + { list.push_back(std::forward(value)); } + +template +void MapInsert(T& map, V&& value) + { map.insert(std::forward(value)); } + /******************************************/ REACT_END /******************************************/ #endif // REACT_TYPETRAITS_H_INCLUDED \ No newline at end of file diff --git a/include/react/detail/state_nodes.h b/include/react/detail/state_nodes.h index aa8c8b85..dbc57fb3 100644 --- a/include/react/detail/state_nodes.h +++ b/include/react/detail/state_nodes.h @@ -171,22 +171,19 @@ class StateFuncNode : public StateNode } virtual UpdateResult Update(TurnId turnId) noexcept override - { - bool changed = false; - + { S newValue = apply([this] (const auto& ... deps) { return this->func_(GetInternals(deps).Value() ...); }, depHolder_); - if (! (this->Value() == newValue)) + if (HasChanged(this->Value(), newValue)) { this->Value() = std::move(newValue); - changed = true; - } - - if (changed) return UpdateResult::changed; + } else + { return UpdateResult::unchanged; + } } private: @@ -439,6 +436,37 @@ class StateInternals std::shared_ptr> nodePtr_; }; +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// StateRefNode +/////////////////////////////////////////////////////////////////////////////////////////////////// +template +class StateRefNode : public StateNode> +{ +public: + StateRefNode(const Group& group, const State& input) : + StateRefNode::StateNode( group, std::cref(GetInternals(input).Value()) ), + input_( input ) + { + this->RegisterMe(); + this->AttachToMe(GetInternals(input).GetNodeId()); + } + + ~StateRefNode() + { + this->DetachFromMe(GetInternals(input_).GetNodeId()); + this->UnregisterMe(); + } + + virtual UpdateResult Update(TurnId turnId) noexcept override + { + this->Value() = std::cref(GetInternals(input_).Value()); + return UpdateResult::changed; + } + +private: + State input_; +}; + /////////////////////////////////////////////////////////////////////////////////////////////////// /// SameGroupOrLink /////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/include/react/state.h b/include/react/state.h index d8235d37..40eeb574 100644 --- a/include/react/state.h +++ b/include/react/state.h @@ -202,10 +202,7 @@ class StateSlot : public State StateSlot& operator=(StateSlot&&) = default; void Set(const State& newInput) - { SetInput(newInput); } - - void operator<<=(const State& newInput) - { SetInput(newInput); } + { SetSlotInput(newInput); } protected: StateSlot(std::shared_ptr>&& nodePtr) : @@ -221,7 +218,7 @@ class StateSlot : public State return std::make_shared>(group, SameGroupOrLink(group, input)); } - void SetInput(const State& newInput) + void SetSlotInput(const State& newInput) { using REACT_IMPL::NodeId; using REACT_IMPL::StateSlotNode; @@ -282,6 +279,18 @@ class StateLink : public State } }; +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// CreateRef +/////////////////////////////////////////////////////////////////////////////////////////////////// +template +auto CreateRef(const State& state) -> State> +{ + using REACT_IMPL::StateRefNode; + using REACT_IMPL::CreateWrappedNode; + + return CreateWrappedNode>, StateRefNode>(state.GetGroup(), state); +} + /////////////////////////////////////////////////////////////////////////////////////////////////// /// ObjectContext /////////////////////////////////////////////////////////////////////////////////////////////////// From 90057e3e977d4d5d53a03bd5fb4c5f2c82b0e4e5 Mon Sep 17 00:00:00 2001 From: schlangster Date: Wed, 1 Nov 2017 01:30:02 +0100 Subject: [PATCH 67/75] Cleanup. --- include/react/detail/event_nodes.h | 14 ++++---------- include/react/event.h | 18 +++++++++--------- 2 files changed, 13 insertions(+), 19 deletions(-) diff --git a/include/react/detail/event_nodes.h b/include/react/detail/event_nodes.h index c918afec..fce5b4b1 100644 --- a/include/react/detail/event_nodes.h +++ b/include/react/detail/event_nodes.h @@ -45,12 +45,6 @@ template class EventNode : public NodeBase { public: - EventNode(EventNode&&) = default; - EventNode& operator=(EventNode&&) = default; - - EventNode(const EventNode&) = delete; - EventNode& operator=(const EventNode&) = delete; - explicit EventNode(const Group& group) : EventNode::NodeBase( group ) { } @@ -161,7 +155,7 @@ class EventSlotNode : public EventNode ~EventSlotNode() { - RemoveAllInputs(); + RemoveAllSlotInputs(); this->DetachFromMe(inputNodeId_); this->UnregisterMe(); @@ -182,7 +176,7 @@ class EventSlotNode : public EventNode return UpdateResult::unchanged; } - void AddInput(const Event& input) + void AddSlotInput(const Event& input) { auto it = std::find(inputs_.begin(), inputs_.end(), input); if (it == inputs_.end()) @@ -192,7 +186,7 @@ class EventSlotNode : public EventNode } } - void RemoveInput(const Event& input) + void RemoveSlotInput(const Event& input) { auto it = std::find(inputs_.begin(), inputs_.end(), input); if (it != inputs_.end()) @@ -202,7 +196,7 @@ class EventSlotNode : public EventNode } } - void RemoveAllInputs() + void RemoveAllSlotInputs() { for (const auto& e : inputs_) this->DetachFromMe(GetInternals(e).GetNodeId()); diff --git a/include/react/event.h b/include/react/event.h index aeaaa6f6..8dd05d46 100644 --- a/include/react/event.h +++ b/include/react/event.h @@ -192,13 +192,13 @@ class EventSlot : public Event EventSlot& operator=(EventSlot&&) = default; void Add(const Event& input) - { AddInput(input); } + { AddSlotInput(input); } void Remove(const Event& input) - { RemoveInput(input); } + { RemoveSlotInput(input); } void RemoveAll() - { RemoveAllInputs(); } + { RemoveAllSlotInputs(); } protected: EventSlot(std::shared_ptr>&& nodePtr) : @@ -212,7 +212,7 @@ class EventSlot : public Event return std::make_shared>(group); } - void AddInput(const Event& input) + void AddSlotInput(const Event& input) { using REACT_IMPL::NodeId; using SlotNodeType = REACT_IMPL::EventSlotNode; @@ -222,10 +222,10 @@ class EventSlot : public Event NodeId nodeId = castedPtr->GetInputNodeId(); auto& graphPtr = GetInternals(this->GetGroup()).GetGraphPtr(); - graphPtr->PushInput(nodeId, [this, castedPtr, &input] { castedPtr->AddInput(SameGroupOrLink(GetGroup(), input)); }); + graphPtr->PushInput(nodeId, [this, castedPtr, &input] { castedPtr->AddSlotInput(SameGroupOrLink(GetGroup(), input)); }); } - void RemoveInput(const Event& input) + void RemoveSlotInput(const Event& input) { using REACT_IMPL::NodeId; using SlotNodeType = REACT_IMPL::EventSlotNode; @@ -235,10 +235,10 @@ class EventSlot : public Event NodeId nodeId = castedPtr->GetInputNodeId(); auto& graphPtr = GetInternals(this->GetGroup()).GetGraphPtr(); - graphPtr->PushInput(nodeId, [this, castedPtr, &input] { castedPtr->RemoveInput(SameGroupOrLink(GetGroup(), input)); }); + graphPtr->PushInput(nodeId, [this, castedPtr, &input] { castedPtr->RemoveSlotInput(SameGroupOrLink(GetGroup(), input)); }); } - void RemoveAllInputs() + void RemoveAllSlotInputs() { using REACT_IMPL::NodeId; using SlotNodeType = REACT_IMPL::EventSlotNode; @@ -248,7 +248,7 @@ class EventSlot : public Event NodeId nodeId = castedPtr->GetInputNodeId(); auto& graphPtr = GetInternals(this->GetGroup()).GetGraphPtr(); - graphPtr->PushInput(nodeId, [castedPtr] { castedPtr->RemoveAllInputs(); }); + graphPtr->PushInput(nodeId, [castedPtr] { castedPtr->RemoveAllSlotInputs(); }); } }; From 8e1f42fe37558d8ad224d6bdc8e2f6117e36aee2 Mon Sep 17 00:00:00 2001 From: schlangster Date: Wed, 1 Nov 2017 01:32:28 +0100 Subject: [PATCH 68/75] WIP: Flattening for nested state. --- examples/src/BasicAlgorithms.cpp | 120 ++++++++++++- include/react/algorithm.h | 84 +++++++++ include/react/detail/algorithm_nodes.h | 236 +++++++++++++++++++++++++ include/react/detail/graph_interface.h | 3 +- 4 files changed, 440 insertions(+), 3 deletions(-) diff --git a/examples/src/BasicAlgorithms.cpp b/examples/src/BasicAlgorithms.cpp index d6f8aced..b2fa8b96 100644 --- a/examples/src/BasicAlgorithms.cpp +++ b/examples/src/BasicAlgorithms.cpp @@ -340,17 +340,133 @@ namespace example6 } } + +using namespace react; + + +template +class MyContainer { }; + +template +struct Flattened : public C +{ + using C::C; + + Flattened(const C& base) : + C( base ) + { } + + Flattened(const C& base, int m) : + C( base ), + mode( m ) + { } + + template + T* Flatten(State& signal) + { + if (mode == 1) + { + memberIds_.push_back(GetInternals(signal).GetNodeId()); + } + + return &GetInternals(signal).Value(); + } + +public: + int mode = 0; + std::vector memberIds_; +}; + +Group g; + +struct MyClass +{ + StateVar a = StateVar::Create(g, 10); + StateVar b = StateVar::Create(g, 20); + + int hello = 12435; + + bool operator==(const MyClass& other) + { return hello == other.hello; } + + struct Flat; +}; + +struct MyClass::Flat : public Flattened +{ + using Flattened::Flattened; + + int* a = this->Flatten(MyClass::a); + int* b = this->Flatten(MyClass::b); +}; + + +void test1() +{ + using namespace react; + + /*StateVar x; + State y; + State z; + + State>> list; + State>> map; + + State> flatlist = FlattenList(list); + State> flatmap = FlattenMap(map); + + MyClass cls1; + MyClass::Flat cls2(cls1); + + StateVar> sig; + + Flatten(g, sig);*/ + + StateVar st = StateVar::Create(g); + + State> ref = CreateRef(st); + + auto obs2 = Observer::Create([] (const MyClass& obj) + { + printf("aa %d\n", obj.hello); + }, ref); + + auto flat = FlattenObject(st); + + auto flat2 = FlattenObject(ref); + + auto obs = Observer::Create([] (const MyClass::Flat& obj) + { + int x = *obj.a; + int y = *obj.b; + printf("%d\n", x); + printf("%d\n", y); + }, flat2); + + + GetInternals(st).Value().a.Set(999); + + MyClass a2{ }; + a2.hello = 3333; + + st.Set(a2); + st.Set(a2); + +} + /////////////////////////////////////////////////////////////////////////////////////////////////// /// Run examples /////////////////////////////////////////////////////////////////////////////////////////////////// int main() { - example1::Run(); + /*example1::Run(); example2::Run(); example3::Run(); example4::Run(); example5::Run(); - example6::Run(); + example6::Run();*/ + + test1(); return 0; } \ No newline at end of file diff --git a/include/react/algorithm.h b/include/react/algorithm.h index 075f3d3c..1d95bbce 100644 --- a/include/react/algorithm.h +++ b/include/react/algorithm.h @@ -169,6 +169,90 @@ template auto Pulse(const State& state, const Event& evnt) -> Event { return Pulse(state.GetGroup(), state, evnt); } +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// Flatten +/////////////////////////////////////////////////////////////////////////////////////////////////// +template +auto Flatten(const Group& group, const State>& state) -> State +{ + using REACT_IMPL::FlattenStateNode; + using REACT_IMPL::SameGroupOrLink; + using REACT_IMPL::CreateWrappedNode; + + return CreateWrappedNode, FlattenStateNode>(group, SameGroupOrLink(group, state)); +} + +template +auto Flatten(const State>& state) -> State + { return Flatten(state.GetGroup(), state); } + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// FlattenList +/////////////////////////////////////////////////////////////////////////////////////////////////// +template