From b26f1729de084c5712b4e165e7967c5d734757c0 Mon Sep 17 00:00:00 2001 From: schlangster Date: Mon, 28 Jul 2014 20:02:14 +0200 Subject: [PATCH 01/86] Added ReactPlayer tool. --- tools/ReactPlayer/ReactPlayer.swf | Bin 0 -> 13905 bytes tools/ReactPlayer/readme.txt | 8 ++++++++ 2 files changed, 8 insertions(+) create mode 100644 tools/ReactPlayer/ReactPlayer.swf create mode 100644 tools/ReactPlayer/readme.txt diff --git a/tools/ReactPlayer/ReactPlayer.swf b/tools/ReactPlayer/ReactPlayer.swf new file mode 100644 index 0000000000000000000000000000000000000000..ee457a7c92999db5bab5c1804898901227834e32 GIT binary patch literal 13905 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 RqIW2BVhCTz(3;UA{|CuOHLm~w literal 0 HcmV?d00001 diff --git a/tools/ReactPlayer/readme.txt b/tools/ReactPlayer/readme.txt new file mode 100644 index 00000000..6d22437d --- /dev/null +++ b/tools/ReactPlayer/readme.txt @@ -0,0 +1,8 @@ +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 1bf14350c7fe3b328f9c6aa58487e9093795f30c Mon Sep 17 00:00:00 2001 From: schlangster Date: Tue, 29 Jul 2014 00:18:26 +0200 Subject: [PATCH 02/86] Added x64 platform to MVSC solution. --- project/msvc/CppReact.sln | 46 +++++++++++ project/msvc/CppReact.vcxproj | 72 ++++++++++++++++++ project/msvc/CppReactBenchmark.vcxproj | 65 ++++++++++++++++ project/msvc/CppReactExample.vcxproj | 68 +++++++++++++++++ project/msvc/CppReactTest.vcxproj | 76 +++++++++++++++++++ project/msvc/Example_BasicAlgorithms.vcxproj | 62 +++++++++++++++ project/msvc/Example_BasicComposition.vcxproj | 62 +++++++++++++++ project/msvc/Example_BasicEvents.vcxproj | 62 +++++++++++++++ project/msvc/Example_BasicObservers.vcxproj | 62 +++++++++++++++ project/msvc/Example_BasicReactors.vcxproj | 62 +++++++++++++++ project/msvc/Example_BasicSignals.vcxproj | 62 +++++++++++++++ .../msvc/Example_BasicSynchronization.vcxproj | 62 +++++++++++++++ 12 files changed, 761 insertions(+) diff --git a/project/msvc/CppReact.sln b/project/msvc/CppReact.sln index 08c58e9d..b414852d 100644 --- a/project/msvc/CppReact.sln +++ b/project/msvc/CppReact.sln @@ -36,53 +36,99 @@ EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 Release|Win32 = Release|Win32 + Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {5E56AAB9-4E33-4B9E-A315-E85CEDB75CF1}.Debug|Win32.ActiveCfg = Debug|Win32 {5E56AAB9-4E33-4B9E-A315-E85CEDB75CF1}.Debug|Win32.Build.0 = Debug|Win32 + {5E56AAB9-4E33-4B9E-A315-E85CEDB75CF1}.Debug|x64.ActiveCfg = Debug|x64 + {5E56AAB9-4E33-4B9E-A315-E85CEDB75CF1}.Debug|x64.Build.0 = Debug|x64 {5E56AAB9-4E33-4B9E-A315-E85CEDB75CF1}.Release|Win32.ActiveCfg = Release|Win32 {5E56AAB9-4E33-4B9E-A315-E85CEDB75CF1}.Release|Win32.Build.0 = Release|Win32 + {5E56AAB9-4E33-4B9E-A315-E85CEDB75CF1}.Release|x64.ActiveCfg = Release|x64 + {5E56AAB9-4E33-4B9E-A315-E85CEDB75CF1}.Release|x64.Build.0 = Release|x64 {F9115FB9-61DD-4B3C-BCE8-7D26372B05F7}.Debug|Win32.ActiveCfg = Debug|Win32 {F9115FB9-61DD-4B3C-BCE8-7D26372B05F7}.Debug|Win32.Build.0 = Debug|Win32 + {F9115FB9-61DD-4B3C-BCE8-7D26372B05F7}.Debug|x64.ActiveCfg = Debug|x64 + {F9115FB9-61DD-4B3C-BCE8-7D26372B05F7}.Debug|x64.Build.0 = Debug|x64 {F9115FB9-61DD-4B3C-BCE8-7D26372B05F7}.Release|Win32.ActiveCfg = Release|Win32 {F9115FB9-61DD-4B3C-BCE8-7D26372B05F7}.Release|Win32.Build.0 = Release|Win32 + {F9115FB9-61DD-4B3C-BCE8-7D26372B05F7}.Release|x64.ActiveCfg = Release|x64 + {F9115FB9-61DD-4B3C-BCE8-7D26372B05F7}.Release|x64.Build.0 = Release|x64 {52A9EC67-C6A7-453B-AD65-F027CA07AF44}.Debug|Win32.ActiveCfg = Debug|Win32 {52A9EC67-C6A7-453B-AD65-F027CA07AF44}.Debug|Win32.Build.0 = Debug|Win32 + {52A9EC67-C6A7-453B-AD65-F027CA07AF44}.Debug|x64.ActiveCfg = Debug|x64 + {52A9EC67-C6A7-453B-AD65-F027CA07AF44}.Debug|x64.Build.0 = Debug|x64 {52A9EC67-C6A7-453B-AD65-F027CA07AF44}.Release|Win32.ActiveCfg = Release|Win32 {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 + {617019A2-97BE-4A60-8EC4-3547D8C54533}.Debug|x64.Build.0 = Debug|x64 {617019A2-97BE-4A60-8EC4-3547D8C54533}.Release|Win32.ActiveCfg = Release|Win32 {617019A2-97BE-4A60-8EC4-3547D8C54533}.Release|Win32.Build.0 = Release|Win32 + {617019A2-97BE-4A60-8EC4-3547D8C54533}.Release|x64.ActiveCfg = Release|x64 + {617019A2-97BE-4A60-8EC4-3547D8C54533}.Release|x64.Build.0 = Release|x64 {D7B70D3B-F14D-4A85-B164-EAB88C358E85}.Debug|Win32.ActiveCfg = Debug|Win32 {D7B70D3B-F14D-4A85-B164-EAB88C358E85}.Debug|Win32.Build.0 = Debug|Win32 + {D7B70D3B-F14D-4A85-B164-EAB88C358E85}.Debug|x64.ActiveCfg = Debug|x64 + {D7B70D3B-F14D-4A85-B164-EAB88C358E85}.Debug|x64.Build.0 = Debug|x64 {D7B70D3B-F14D-4A85-B164-EAB88C358E85}.Release|Win32.ActiveCfg = Release|Win32 {D7B70D3B-F14D-4A85-B164-EAB88C358E85}.Release|Win32.Build.0 = Release|Win32 + {D7B70D3B-F14D-4A85-B164-EAB88C358E85}.Release|x64.ActiveCfg = Release|x64 + {D7B70D3B-F14D-4A85-B164-EAB88C358E85}.Release|x64.Build.0 = Release|x64 {BD777649-97F1-4810-BF21-CB27F7672BF4}.Debug|Win32.ActiveCfg = Debug|Win32 {BD777649-97F1-4810-BF21-CB27F7672BF4}.Debug|Win32.Build.0 = Debug|Win32 + {BD777649-97F1-4810-BF21-CB27F7672BF4}.Debug|x64.ActiveCfg = Debug|x64 + {BD777649-97F1-4810-BF21-CB27F7672BF4}.Debug|x64.Build.0 = Debug|x64 {BD777649-97F1-4810-BF21-CB27F7672BF4}.Release|Win32.ActiveCfg = Release|Win32 {BD777649-97F1-4810-BF21-CB27F7672BF4}.Release|Win32.Build.0 = Release|Win32 + {BD777649-97F1-4810-BF21-CB27F7672BF4}.Release|x64.ActiveCfg = Release|x64 + {BD777649-97F1-4810-BF21-CB27F7672BF4}.Release|x64.Build.0 = Release|x64 {CC66BFA0-D609-46E0-9FD1-F9CC902410B1}.Debug|Win32.ActiveCfg = Debug|Win32 {CC66BFA0-D609-46E0-9FD1-F9CC902410B1}.Debug|Win32.Build.0 = Debug|Win32 + {CC66BFA0-D609-46E0-9FD1-F9CC902410B1}.Debug|x64.ActiveCfg = Debug|x64 + {CC66BFA0-D609-46E0-9FD1-F9CC902410B1}.Debug|x64.Build.0 = Debug|x64 {CC66BFA0-D609-46E0-9FD1-F9CC902410B1}.Release|Win32.ActiveCfg = Release|Win32 {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 + {230C9137-CCD0-47E2-8F1F-2E1DD19984A1}.Debug|x64.Build.0 = Debug|x64 {230C9137-CCD0-47E2-8F1F-2E1DD19984A1}.Release|Win32.ActiveCfg = Release|Win32 {230C9137-CCD0-47E2-8F1F-2E1DD19984A1}.Release|Win32.Build.0 = Release|Win32 + {230C9137-CCD0-47E2-8F1F-2E1DD19984A1}.Release|x64.ActiveCfg = Release|x64 + {230C9137-CCD0-47E2-8F1F-2E1DD19984A1}.Release|x64.Build.0 = Release|x64 {269329F8-A9E1-41AC-9C37-3A82A082A62C}.Debug|Win32.ActiveCfg = Debug|Win32 {269329F8-A9E1-41AC-9C37-3A82A082A62C}.Debug|Win32.Build.0 = Debug|Win32 + {269329F8-A9E1-41AC-9C37-3A82A082A62C}.Debug|x64.ActiveCfg = Debug|x64 + {269329F8-A9E1-41AC-9C37-3A82A082A62C}.Debug|x64.Build.0 = Debug|x64 {269329F8-A9E1-41AC-9C37-3A82A082A62C}.Release|Win32.ActiveCfg = Release|Win32 {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 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/project/msvc/CppReact.vcxproj b/project/msvc/CppReact.vcxproj index d62e935b..16ae1f97 100644 --- a/project/msvc/CppReact.vcxproj +++ b/project/msvc/CppReact.vcxproj @@ -5,10 +5,18 @@ Debug Win32 + + Debug + x64 + Release Win32 + + Release + x64 + {5E56AAB9-4E33-4B9E-A315-E85CEDB75CF1} @@ -21,6 +29,12 @@ v120 MultiByte + + StaticLibrary + true + v120 + MultiByte + StaticLibrary false @@ -28,24 +42,45 @@ true MultiByte + + StaticLibrary + false + v120 + true + MultiByte + + + + + + + $(SolutionDir)..\..\build\$(Configuration)\ $(OutDir)$(ProjectName)\ + + $(SolutionDir)..\..\build\$(Configuration)\ + $(OutDir)$(ProjectName)\ + $(SolutionDir)..\..\build\$(Configuration)\ $(OutDir)$(ProjectName)\ + + $(SolutionDir)..\..\build\$(Configuration)\ + $(OutDir)$(ProjectName)\ + Level3 @@ -62,6 +97,22 @@ $(OutDir)$(TargetName)$(TargetExt) + + + Level3 + Disabled + true + $(SolutionDir)..\..\include;%(AdditionalIncludeDirectories) + true + %(PreprocessorDefinitions) + + + true + + + $(OutDir)$(TargetName)$(TargetExt) + + Level3 @@ -82,9 +133,30 @@ $(OutDir)$(TargetName)$(TargetExt) + + + Level3 + MaxSpeed + true + true + true + $(SolutionDir)..\..\include;%(AdditionalIncludeDirectories) + true + %(PreprocessorDefinitions) + + + true + true + true + + + $(OutDir)$(TargetName)$(TargetExt) + + + diff --git a/project/msvc/CppReactBenchmark.vcxproj b/project/msvc/CppReactBenchmark.vcxproj index 348829f8..7613239a 100644 --- a/project/msvc/CppReactBenchmark.vcxproj +++ b/project/msvc/CppReactBenchmark.vcxproj @@ -5,10 +5,18 @@ Debug Win32 + + Debug + x64 + Release Win32 + + Release + x64 + {F9115FB9-61DD-4B3C-BCE8-7D26372B05F7} @@ -21,6 +29,12 @@ v120 MultiByte + + Application + true + v120 + MultiByte + Application false @@ -28,24 +42,42 @@ true MultiByte + + Application + false + v120 + true + MultiByte + + + + + + + $(SolutionDir)..\..\build\$(Configuration)\ $(OutDir)$(ProjectName)\ + + $(SolutionDir)..\..\build\$(Configuration)\ + $(OutDir)$(ProjectName)\ + $(SolutionDir)..\..\build\$(Configuration)\ $(OutDir)$(ProjectName)\ + Level3 @@ -60,6 +92,20 @@ Console + + + Level3 + Disabled + true + true + $(SolutionDir)..\..\include;%(AdditionalIncludeDirectories) + _CRT_SECURE_NO_WARNINGS;_VARIADIC_MAX=10;%(PreprocessorDefinitions) + + + true + Console + + Level3 @@ -79,6 +125,25 @@ false + + + Level3 + MaxSpeed + true + true + true + true + $(SolutionDir)..\..\include;%(AdditionalIncludeDirectories) + _CRT_SECURE_NO_WARNINGS;_VARIADIC_MAX=10;%(PreprocessorDefinitions) + + + true + true + true + Console + false + + {5e56aab9-4e33-4b9e-a315-e85cedb75cf1} diff --git a/project/msvc/CppReactExample.vcxproj b/project/msvc/CppReactExample.vcxproj index b0277b9b..323c777f 100644 --- a/project/msvc/CppReactExample.vcxproj +++ b/project/msvc/CppReactExample.vcxproj @@ -5,10 +5,18 @@ Debug Win32 + + Debug + x64 + Release Win32 + + Release + x64 + {CC0CD982-AE7D-4797-A122-58E6BBE70DDB} @@ -22,6 +30,12 @@ v120 MultiByte + + Application + true + v120 + MultiByte + Application false @@ -29,24 +43,45 @@ true MultiByte + + Application + false + v120 + true + MultiByte + + + + + + + $(SolutionDir)..\..\build\$(Configuration)\ $(OutDir)$(ProjectName)\ + + $(SolutionDir)..\..\build\$(Configuration)\ + $(OutDir)$(ProjectName)\ + $(SolutionDir)..\..\build\$(Configuration)\ $(OutDir)$(ProjectName)\ + + $(SolutionDir)..\..\build\$(Configuration)\ + $(OutDir)$(ProjectName)\ + Level3 @@ -61,6 +96,20 @@ Console + + + Level3 + Disabled + true + $(SolutionDir)..\..\include;%(AdditionalIncludeDirectories) + true + _VARIADIC_MAX=10;%(PreprocessorDefinitions) + + + true + Console + + Level3 @@ -80,6 +129,25 @@ false + + + Level3 + MaxSpeed + true + true + true + $(SolutionDir)..\..\include;%(AdditionalIncludeDirectories) + true + _VARIADIC_MAX=10;%(PreprocessorDefinitions) + + + true + true + true + Console + false + + {5e56aab9-4e33-4b9e-a315-e85cedb75cf1} diff --git a/project/msvc/CppReactTest.vcxproj b/project/msvc/CppReactTest.vcxproj index 68e94238..ff65e1d5 100644 --- a/project/msvc/CppReactTest.vcxproj +++ b/project/msvc/CppReactTest.vcxproj @@ -5,10 +5,18 @@ Debug Win32 + + Debug + x64 + Release Win32 + + Release + x64 + {52A9EC67-C6A7-453B-AD65-F027CA07AF44} @@ -21,6 +29,12 @@ v120 MultiByte + + Application + true + v120 + MultiByte + Application false @@ -28,24 +42,45 @@ true MultiByte + + Application + false + v120 + true + MultiByte + + + + + + + $(SolutionDir)..\..\build\$(Configuration)\ $(OutDir)$(ProjectName)\ + + $(SolutionDir)..\..\build\$(Configuration)\ + $(OutDir)$(ProjectName)\ + $(SolutionDir)..\..\build\$(Configuration)\ $(OutDir)$(ProjectName)\ + + $(SolutionDir)..\..\build\$(Configuration)\ + $(OutDir)$(ProjectName)\ + Level3 @@ -63,6 +98,24 @@ 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 + + Level3 @@ -85,6 +138,29 @@ false + + + Level3 + MaxSpeed + true + true + true + $(SolutionDir)..\..\include;$(GTestDir)\include;%(AdditionalIncludeDirectories) + _VARIADIC_MAX=10;%(PreprocessorDefinitions) + true + 4503;%(DisableSpecificWarnings) + /bigobj %(AdditionalOptions) + + + true + true + true + $(GTestDir)\msvc\gtest-md\Release;%(AdditionalLibraryDirectories) + gtest.lib;gtest_main-md.lib;%(AdditionalDependencies) + Console + false + + {5e56aab9-4e33-4b9e-a315-e85cedb75cf1} diff --git a/project/msvc/Example_BasicAlgorithms.vcxproj b/project/msvc/Example_BasicAlgorithms.vcxproj index a53d10f8..cd4b6e9b 100644 --- a/project/msvc/Example_BasicAlgorithms.vcxproj +++ b/project/msvc/Example_BasicAlgorithms.vcxproj @@ -5,10 +5,18 @@ Debug Win32 + + Debug + x64 + Release Win32 + + Release + x64 + {617019A2-97BE-4A60-8EC4-3547D8C54533} @@ -21,6 +29,12 @@ v120 MultiByte + + Application + true + v120 + MultiByte + Application false @@ -28,24 +42,45 @@ true MultiByte + + Application + false + v120 + true + MultiByte + + + + + + + $(SolutionDir)..\..\build\$(Configuration)\ $(OutDir)$(ProjectName)\ + + $(SolutionDir)..\..\build\$(Configuration)\ + $(OutDir)$(ProjectName)\ + $(SolutionDir)..\..\build\$(Configuration)\ $(OutDir)$(ProjectName)\ + + $(SolutionDir)..\..\build\$(Configuration)\ + $(OutDir)$(ProjectName)\ + Level3 @@ -58,6 +93,18 @@ Console + + + Level3 + Disabled + true + $(SolutionDir)..\..\include;%(AdditionalIncludeDirectories) + + + true + Console + + Level3 @@ -73,6 +120,21 @@ true + + + Level3 + MaxSpeed + true + true + true + $(SolutionDir)..\..\include;%(AdditionalIncludeDirectories) + + + true + true + true + + {5e56aab9-4e33-4b9e-a315-e85cedb75cf1} diff --git a/project/msvc/Example_BasicComposition.vcxproj b/project/msvc/Example_BasicComposition.vcxproj index ba21df79..8b336087 100644 --- a/project/msvc/Example_BasicComposition.vcxproj +++ b/project/msvc/Example_BasicComposition.vcxproj @@ -5,10 +5,18 @@ Debug Win32 + + Debug + x64 + Release Win32 + + Release + x64 + {D7B70D3B-F14D-4A85-B164-EAB88C358E85} @@ -21,6 +29,12 @@ v120 MultiByte + + Application + true + v120 + MultiByte + Application false @@ -28,24 +42,45 @@ true MultiByte + + Application + false + v120 + true + MultiByte + + + + + + + $(SolutionDir)..\..\build\$(Configuration)\ $(OutDir)$(ProjectName)\ + + $(SolutionDir)..\..\build\$(Configuration)\ + $(OutDir)$(ProjectName)\ + $(SolutionDir)..\..\build\$(Configuration)\ $(OutDir)$(ProjectName)\ + + $(SolutionDir)..\..\build\$(Configuration)\ + $(OutDir)$(ProjectName)\ + Level3 @@ -58,6 +93,18 @@ Console + + + Level3 + Disabled + true + $(SolutionDir)..\..\include;%(AdditionalIncludeDirectories) + + + true + Console + + Level3 @@ -73,6 +120,21 @@ true + + + Level3 + MaxSpeed + true + true + true + $(SolutionDir)..\..\include;%(AdditionalIncludeDirectories) + + + true + true + true + + {5e56aab9-4e33-4b9e-a315-e85cedb75cf1} diff --git a/project/msvc/Example_BasicEvents.vcxproj b/project/msvc/Example_BasicEvents.vcxproj index 2de69525..2e3bad5e 100644 --- a/project/msvc/Example_BasicEvents.vcxproj +++ b/project/msvc/Example_BasicEvents.vcxproj @@ -5,10 +5,18 @@ Debug Win32 + + Debug + x64 + Release Win32 + + Release + x64 + {BD777649-97F1-4810-BF21-CB27F7672BF4} @@ -21,6 +29,12 @@ v120 MultiByte + + Application + true + v120 + MultiByte + Application false @@ -28,24 +42,45 @@ true MultiByte + + Application + false + v120 + true + MultiByte + + + + + + + $(SolutionDir)..\..\build\$(Configuration)\ $(OutDir)$(ProjectName)\ + + $(SolutionDir)..\..\build\$(Configuration)\ + $(OutDir)$(ProjectName)\ + $(SolutionDir)..\..\build\$(Configuration)\ $(OutDir)$(ProjectName)\ + + $(SolutionDir)..\..\build\$(Configuration)\ + $(OutDir)$(ProjectName)\ + Level3 @@ -58,6 +93,18 @@ Console + + + Level3 + Disabled + true + $(SolutionDir)..\..\include;%(AdditionalIncludeDirectories) + + + true + Console + + Level3 @@ -73,6 +120,21 @@ true + + + Level3 + MaxSpeed + true + true + true + $(SolutionDir)..\..\include;%(AdditionalIncludeDirectories) + + + true + true + true + + {5e56aab9-4e33-4b9e-a315-e85cedb75cf1} diff --git a/project/msvc/Example_BasicObservers.vcxproj b/project/msvc/Example_BasicObservers.vcxproj index 4eddc801..f99889bf 100644 --- a/project/msvc/Example_BasicObservers.vcxproj +++ b/project/msvc/Example_BasicObservers.vcxproj @@ -5,10 +5,18 @@ Debug Win32 + + Debug + x64 + Release Win32 + + Release + x64 + {CC66BFA0-D609-46E0-9FD1-F9CC902410B1} @@ -21,6 +29,12 @@ v120 MultiByte + + Application + true + v120 + MultiByte + Application false @@ -28,24 +42,45 @@ true MultiByte + + Application + false + v120 + true + MultiByte + + + + + + + $(SolutionDir)..\..\build\$(Configuration)\ $(OutDir)$(ProjectName)\ + + $(SolutionDir)..\..\build\$(Configuration)\ + $(OutDir)$(ProjectName)\ + $(SolutionDir)..\..\build\$(Configuration)\ $(OutDir)$(ProjectName)\ + + $(SolutionDir)..\..\build\$(Configuration)\ + $(OutDir)$(ProjectName)\ + Level3 @@ -58,6 +93,18 @@ Console + + + Level3 + Disabled + true + $(SolutionDir)..\..\include;%(AdditionalIncludeDirectories) + + + true + Console + + Level3 @@ -73,6 +120,21 @@ true + + + Level3 + MaxSpeed + true + true + true + $(SolutionDir)..\..\include;%(AdditionalIncludeDirectories) + + + true + true + true + + diff --git a/project/msvc/Example_BasicReactors.vcxproj b/project/msvc/Example_BasicReactors.vcxproj index 92ab34cd..f05f8265 100644 --- a/project/msvc/Example_BasicReactors.vcxproj +++ b/project/msvc/Example_BasicReactors.vcxproj @@ -5,10 +5,18 @@ Debug Win32 + + Debug + x64 + Release Win32 + + Release + x64 + {D976F4D4-B472-4709-BFB5-B1BEEA1F7E96} @@ -21,6 +29,12 @@ v120 MultiByte + + Application + true + v120 + MultiByte + Application false @@ -28,24 +42,45 @@ true MultiByte + + Application + false + v120 + true + MultiByte + + + + + + + $(SolutionDir)..\..\build\$(Configuration)\ $(OutDir)$(ProjectName)\ + + $(SolutionDir)..\..\build\$(Configuration)\ + $(OutDir)$(ProjectName)\ + $(SolutionDir)..\..\build\$(Configuration)\ $(OutDir)$(ProjectName)\ + + $(SolutionDir)..\..\build\$(Configuration)\ + $(OutDir)$(ProjectName)\ + Level3 @@ -58,6 +93,18 @@ Console + + + Level3 + Disabled + true + $(SolutionDir)..\..\include;%(AdditionalIncludeDirectories) + + + true + Console + + Level3 @@ -73,6 +120,21 @@ true + + + Level3 + MaxSpeed + true + true + true + $(SolutionDir)..\..\include;%(AdditionalIncludeDirectories) + + + true + true + true + + diff --git a/project/msvc/Example_BasicSignals.vcxproj b/project/msvc/Example_BasicSignals.vcxproj index 495b1813..653861ba 100644 --- a/project/msvc/Example_BasicSignals.vcxproj +++ b/project/msvc/Example_BasicSignals.vcxproj @@ -5,10 +5,18 @@ Debug Win32 + + Debug + x64 + Release Win32 + + Release + x64 + {230C9137-CCD0-47E2-8F1F-2E1DD19984A1} @@ -21,6 +29,12 @@ v120 MultiByte + + Application + true + v120 + MultiByte + Application false @@ -28,24 +42,45 @@ true MultiByte + + Application + false + v120 + true + MultiByte + + + + + + + $(SolutionDir)..\..\build\$(Configuration)\ $(OutDir)$(ProjectName)\ + + $(SolutionDir)..\..\build\$(Configuration)\ + $(OutDir)$(ProjectName)\ + $(SolutionDir)..\..\build\$(Configuration)\ $(OutDir)$(ProjectName)\ + + $(SolutionDir)..\..\build\$(Configuration)\ + $(OutDir)$(ProjectName)\ + Level3 @@ -58,6 +93,18 @@ Console + + + Level3 + Disabled + true + $(SolutionDir)..\..\include;%(AdditionalIncludeDirectories) + + + true + Console + + Level3 @@ -73,6 +120,21 @@ true + + + Level3 + MaxSpeed + true + true + true + $(SolutionDir)..\..\include;%(AdditionalIncludeDirectories) + + + true + true + true + + {5e56aab9-4e33-4b9e-a315-e85cedb75cf1} diff --git a/project/msvc/Example_BasicSynchronization.vcxproj b/project/msvc/Example_BasicSynchronization.vcxproj index 5369559a..919643b3 100644 --- a/project/msvc/Example_BasicSynchronization.vcxproj +++ b/project/msvc/Example_BasicSynchronization.vcxproj @@ -5,10 +5,18 @@ Debug Win32 + + Debug + x64 + Release Win32 + + Release + x64 + {269329F8-A9E1-41AC-9C37-3A82A082A62C} @@ -21,6 +29,12 @@ v120 MultiByte + + Application + true + v120 + MultiByte + Application false @@ -28,24 +42,45 @@ true MultiByte + + Application + false + v120 + true + MultiByte + + + + + + + $(SolutionDir)..\..\build\$(Configuration)\ $(OutDir)$(ProjectName)\ + + $(SolutionDir)..\..\build\$(Configuration)\ + $(OutDir)$(ProjectName)\ + $(SolutionDir)..\..\build\$(Configuration)\ $(OutDir)$(ProjectName)\ + + $(SolutionDir)..\..\build\$(Configuration)\ + $(OutDir)$(ProjectName)\ + Level3 @@ -58,6 +93,18 @@ Console + + + Level3 + Disabled + true + $(SolutionDir)..\..\include;%(AdditionalIncludeDirectories) + + + true + Console + + Level3 @@ -73,6 +120,21 @@ true + + + Level3 + MaxSpeed + true + true + true + $(SolutionDir)..\..\include;%(AdditionalIncludeDirectories) + + + true + true + true + + From 2b35b924dded93b7e640968fc3568fbb4f4cfa0f Mon Sep 17 00:00:00 2001 From: schlangster Date: Tue, 29 Jul 2014 00:30:33 +0200 Subject: [PATCH 03/86] Fixed #1. --- benchmarks/src/BenchmarkGrid.h | 6 +++--- benchmarks/src/BenchmarkLifeSim.h | 2 +- src/engine/PulsecountEngine.cpp | 11 +++++++---- src/engine/SubtreeEngine.cpp | 5 ++++- 4 files changed, 15 insertions(+), 9 deletions(-) diff --git a/benchmarks/src/BenchmarkGrid.h b/benchmarks/src/BenchmarkGrid.h index f1e6af3c..551f3db8 100644 --- a/benchmarks/src/BenchmarkGrid.h +++ b/benchmarks/src/BenchmarkGrid.h @@ -35,7 +35,7 @@ class GridGraphGenerator using Func2T = std::function; using SignalVectT = std::vector; - using WidthVectT = std::vector; + using WidthVectT = std::vector; SignalVectT InputSignals; SignalVectT OutputSignals; @@ -56,9 +56,9 @@ class GridGraphGenerator SignalVectT* curBuf = &buf1; SignalVectT* nextBuf = &buf2; - int curWidth = InputSignals.size(); + size_t curWidth = InputSignals.size(); - int nodeCount = 1; + size_t nodeCount = 1; nodeCount += curWidth; for (auto targetWidth : Widths) diff --git a/benchmarks/src/BenchmarkLifeSim.h b/benchmarks/src/BenchmarkLifeSim.h index 26e5760d..b53856dd 100644 --- a/benchmarks/src/BenchmarkLifeSim.h +++ b/benchmarks/src/BenchmarkLifeSim.h @@ -288,7 +288,7 @@ struct Benchmark_LifeSim : public BenchmarkBase vector>> animals; std::mt19937 gen( 2015 ); - std::uniform_int_distribution dist( 0u, theWorld.Regions.size()-1 ); + std::uniform_int_distribution dist( 0u, theWorld.Regions.size()-1 ); for (int i=0; i void spawnTasks ( task& rootTask, task_list& spawnList, - const uint count, TIt start, TIt end, + const size_t count, TIt start, TIt end, TArgs& ... args ) { - rootTask.set_ref_count(1 + count); + assert(1 + count <= + static_cast((std::numeric_limits::max)())); - for (uint i=0; i < (count - 1); i++) + rootTask.set_ref_count(1 + static_cast(count)); + + for (size_t i=0; i < (count - 1); i++) { spawnList.push_back(*new(rootTask.allocate_child()) TTask(args ..., start, start + chunk_size)); @@ -230,7 +233,7 @@ void spawnTasks void EngineBase::Propagate(Turn& turn) { - const uint initialTaskCount = (changedInputs_.size() - 1) / chunk_size + 1; + const size_t initialTaskCount = (changedInputs_.size() - 1) / chunk_size + 1; spawnTasks(rootTask_, spawnList_, initialTaskCount, changedInputs_.begin(), changedInputs_.end()); diff --git a/src/engine/SubtreeEngine.cpp b/src/engine/SubtreeEngine.cpp index 21d54880..9189c697 100644 --- a/src/engine/SubtreeEngine.cpp +++ b/src/engine/SubtreeEngine.cpp @@ -178,7 +178,10 @@ void EngineBase::Propagate(Turn& turn) // Phase 2 isInPhase2_ = true; - rootTask_.set_ref_count(1 + subtreeRoots_.size()); + assert((1 + subtreeRoots_.size()) <= + static_cast((std::numeric_limits::max)())); + + rootTask_.set_ref_count(1 + static_cast(subtreeRoots_.size())); for (auto* node : subtreeRoots_) { From aeb7c84f4baff04fab0992ece831df525a1d60c8 Mon Sep 17 00:00:00 2001 From: schlangster Date: Tue, 29 Jul 2014 00:33:42 +0200 Subject: [PATCH 04/86] Added missing reactive types to TypeTraits.h. --- include/react/TypeTraits.h | 39 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/include/react/TypeTraits.h b/include/react/TypeTraits.h index 3b14e7a7..7141ac14 100644 --- a/include/react/TypeTraits.h +++ b/include/react/TypeTraits.h @@ -34,6 +34,15 @@ class EventSource; template class TempEvents; +template +class Observer; + +template +class ScopedObserver; + +template +class Continuation; + /////////////////////////////////////////////////////////////////////////////////////////////////// /// IsSignal /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -64,6 +73,27 @@ 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; }; + +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; }; + /////////////////////////////////////////////////////////////////////////////////////////////////// /// IsReactive /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -88,6 +118,15 @@ 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; }; + /////////////////////////////////////////////////////////////////////////////////////////////////// /// RemoveInput /////////////////////////////////////////////////////////////////////////////////////////////////// From 3ca6720022559c08c5ce4601e4ef83284481ff3b Mon Sep 17 00:00:00 2001 From: schlangster Date: Tue, 29 Jul 2014 00:41:41 +0200 Subject: [PATCH 05/86] Added SetWeightHint and did some refactoring in the process: * SetWeightHint is added as a member function to all reactive types. * Moved NodeUpdateTimer to NodeBase. * Got rid of domain specific registry. Instead, unique_ptrs to observers are stored per subject. * Moved internals from Domain.h to DomainBase.h. * Added common base classes for reactive types. * Added some missing constructors & assignment operators & IsValid(). * Removed NodePtr() from public interface. Replaced by internal friend function GetNodePtr(). --- include/react/Algorithm.h | 14 +- include/react/Domain.h | 237 ++-------------- include/react/Event.h | 158 +++++++---- include/react/Observer.h | 131 +++++---- include/react/Reactor.h | 6 +- include/react/Signal.h | 171 +++++++---- include/react/common/Timing.h | 20 +- include/react/detail/DomainBase.h | 265 ++++++++++++++++++ include/react/detail/EventBase.h | 6 +- include/react/detail/ObserverBase.h | 122 ++------ include/react/detail/ReactiveBase.h | 104 +++++-- include/react/detail/ReactiveInput.h | 8 +- include/react/detail/SignalBase.h | 6 +- include/react/detail/graph/AlgorithmNodes.h | 32 +-- .../react/detail/graph/ContinuationNodes.h | 3 +- include/react/detail/graph/EventNodes.h | 23 +- include/react/detail/graph/GraphBase.h | 58 +++- include/react/detail/graph/ObserverNodes.h | 39 +-- include/react/detail/graph/ReactorNodes.h | 4 +- include/react/detail/graph/SignalNodes.h | 14 +- project/msvc/CppReact.vcxproj.filters | 3 + 21 files changed, 819 insertions(+), 605 deletions(-) create mode 100644 include/react/detail/DomainBase.h diff --git a/include/react/Algorithm.h b/include/react/Algorithm.h index 90af2917..2f0e7730 100644 --- a/include/react/Algorithm.h +++ b/include/react/Algorithm.h @@ -55,7 +55,7 @@ auto Hold(const Events& events, V&& init) return Signal( std::make_shared>( - std::forward(init), events.NodePtr())); + std::forward(init), GetNodePtr(events))); } /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -73,7 +73,7 @@ auto Monitor(const Signal& target) return Events( std::make_shared>( - target.NodePtr())); + GetNodePtr(target))); } /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -103,7 +103,7 @@ auto Iterate(const Events& events, V&& init, FIn&& func) return Signal( std::make_shared( - std::forward(init), events.NodePtr(), std::forward(func))); + std::forward(init), GetNodePtr(events), std::forward(func))); } /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -146,8 +146,8 @@ auto Iterate(const Events& events, V&& init, { return Signal( std::make_shared( - std::forward(MyInit), MySource.NodePtr(), - std::forward(MyFunc), deps.NodePtr() ...)); + std::forward(MyInit), GetNodePtr(MySource), + std::forward(MyFunc), GetNodePtr(deps) ...)); } const Events& MySource; @@ -176,7 +176,7 @@ auto Snapshot(const Events& trigger, const Signal& target) return Signal( std::make_shared>( - target.NodePtr(), trigger.NodePtr())); + GetNodePtr(target), GetNodePtr(trigger))); } @@ -197,7 +197,7 @@ auto Pulse(const Events& trigger, const Signal& target) return Events( std::make_shared>( - target.NodePtr(), trigger.NodePtr())); + GetNodePtr(target), GetNodePtr(trigger))); } /////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/include/react/Domain.h b/include/react/Domain.h index 54896fe5..548560a2 100644 --- a/include/react/Domain.h +++ b/include/react/Domain.h @@ -14,8 +14,9 @@ #include #include -#include "react/detail/IReactiveEngine.h" +#include "react/detail/DomainBase.h" #include "react/detail/ReactiveInput.h" + #include "react/detail/graph/ContinuationNodes.h" #ifdef REACT_ENABLE_LOGGING @@ -23,11 +24,6 @@ #include "react/logging/EventRecords.h" #endif //REACT_ENABLE_LOGGING -// Include all engines for convenience -#include "react/engine/PulsecountEngine.h" -#include "react/engine/SubtreeEngine.h" -#include "react/engine/ToposortEngine.h" - /*****************************************/ REACT_BEGIN /*****************************************/ /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -79,18 +75,18 @@ using REACT_IMPL::allow_merging; #endif //REACT_ENABLE_LOGGING // Domain modes -enum EDomainMode -{ - sequential, - sequential_concurrent, - parallel, - parallel_concurrent -}; +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; + /////////////////////////////////////////////////////////////////////////////////////////////////// /// TransactionStatus /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -139,101 +135,38 @@ class TransactionStatus friend void AsyncTransaction(TransactionFlagsT flags, TransactionStatus& status, F&& func); }; -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// 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 -}; - /////////////////////////////////////////////////////////////////////////////////////////////////// /// Continuation /////////////////////////////////////////////////////////////////////////////////////////////////// template < - typename TSourceDomain, - typename TTargetDomain + typename D, + typename D2 > -class Continuation +class Continuation : public REACT_IMPL::ContinuationBase { - using NodePtrT = REACT_IMPL::NodeBasePtrT; +private: + using NodePtrT = REACT_IMPL::NodeBasePtrT; public: - using SourceDomainT = TSourceDomain; - using TargetDomainT = TTargetDomain; + using SourceDomainT = D; + using TargetDomainT = D2; Continuation() = default; - Continuation(const Continuation&) = delete; - Continuation& operator=(const Continuation&) = delete; Continuation(Continuation&& other) : - nodePtr_( std::move(other.nodePtr_) ) + Continuation::ContinuationBase( std::move(other) ) {} explicit Continuation(NodePtrT&& nodePtr) : - nodePtr_( std::move(nodePtr) ) - {} + Continuation::ContinuationBase( std::move(nodePtr) ) + {} Continuation& operator=(Continuation&& other) { - nodePtr_ = std::move(other.nodePtr_); + Continuation::ContinuationBase::operator=( std::move(other) ); return *this; } - -private: - NodePtrT nodePtr_; }; /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -257,7 +190,7 @@ auto MakeContinuation(TransactionFlagsT flags, const Signal& trigger, FIn&& return Continuation( std::make_shared>( - flags, trigger.NodePtr(), std::forward(func))); + flags, GetNodePtr(trigger), std::forward(func))); } template @@ -294,7 +227,7 @@ auto MakeContinuation(TransactionFlagsT flags, const Events& trigger, FIn&& return Continuation( std::make_shared>( - flags, trigger.NodePtr(), std::forward(func))); + flags, GetNodePtr(trigger), std::forward(func))); } template @@ -345,11 +278,11 @@ auto MakeContinuation(TransactionFlagsT flags, const Events& trigger, return Continuation( std::make_shared>( MyFlags, - MyTrigger.NodePtr(), - std::forward(MyFunc), deps.NodePtr() ...)); + GetNodePtr(MyTrigger), + std::forward(MyFunc), GetNodePtr(deps) ...)); } - TransactionFlagsT MyFlags; + TransactionFlagsT MyFlags; const Events& MyTrigger; FIn MyFunc; }; @@ -437,130 +370,12 @@ void AsyncTransaction(TransactionFlagsT flags, TransactionStatus& status, F&& fu /******************************************/ REACT_END /******************************************/ -/***************************************/ REACT_IMPL_BEGIN /**************************************/ - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// 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(); - DomainSpecificObserverRegistry::Instance(); - DomainSpecificInputManager::Instance(); - } -}; - -/****************************************/ REACT_IMPL_END /***************************************/ - /////////////////////////////////////////////////////////////////////////////////////////////////// /// Domain definition macro /////////////////////////////////////////////////////////////////////////////////////////////////// #define REACTIVE_DOMAIN(name, ...) \ struct name : \ - public REACT::DomainBase> {}; \ + public REACT_IMPL::DomainBase> {}; \ REACT_IMPL::DomainInitializer name ## _initializer_; /////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/include/react/Event.h b/include/react/Event.h index fed4c33c..550ef5ac 100644 --- a/include/react/Event.h +++ b/include/react/Event.h @@ -42,6 +42,8 @@ class Signal; template class SignalPack; +using REACT_IMPL::WeightHint; + /////////////////////////////////////////////////////////////////////////////////////////////////// /// MakeEventSource /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -79,7 +81,7 @@ auto Merge(const Events& arg1, const Events& ... args) return TempEvents( std::make_shared>( - arg1.NodePtr(), args.NodePtr() ...)); + GetNodePtr(arg1), GetNodePtr(args) ...)); } template @@ -105,7 +107,7 @@ auto operator|(const TLeftEvents& lhs, const TRightEvents& rhs) return TempEvents( std::make_shared>( - lhs.NodePtr(), rhs.NodePtr())); + GetNodePtr(lhs), GetNodePtr(rhs))); } template @@ -149,7 +151,7 @@ auto operator|(TempEvents&& lhs, const TRightEvents& rhs) return TempEvents( std::make_shared>( - lhs.StealOp(), rhs.NodePtr())); + lhs.StealOp(), GetNodePtr(rhs))); } template @@ -173,7 +175,7 @@ auto operator|(const TLeftEvents& lhs, TempEvents&& rhs) return TempEvents( std::make_shared>( - lhs.NodePtr(), rhs.StealOp())); + GetNodePtr(lhs), rhs.StealOp())); } /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -195,7 +197,7 @@ auto Filter(const Events& src, FIn&& filter) return TempEvents( std::make_shared>( - std::forward(filter), src.NodePtr())); + std::forward(filter), GetNodePtr(src))); } template @@ -246,7 +248,7 @@ auto Filter(const Events& source, const SignalPack& depPac { return Events( std::make_shared>( - MySource.NodePtr(), std::forward(MyFunc), deps.NodePtr() ...)); + GetNodePtr(MySource), std::forward(MyFunc), GetNodePtr(deps) ...)); } const Events& MySource; @@ -278,7 +280,7 @@ auto Transform(const Events& src, FIn&& func) return TempEvents( std::make_shared>( - std::forward(func), src.NodePtr())); + std::forward(func), GetNodePtr(src))); } template @@ -331,7 +333,7 @@ auto Transform(const Events& source, const SignalPack& d { return Events( std::make_shared>( - MySource.NodePtr(), std::forward(MyFunc), deps.NodePtr() ...)); + GetNodePtr(MySource), std::forward(MyFunc), GetNodePtr(deps) ...)); } const Events& MySource; @@ -351,12 +353,12 @@ template typename D, typename TInnerValue > -auto Flatten(const Signal>& node) +auto Flatten(const Signal>& outer) -> Events { return Events( std::make_shared, TInnerValue>>( - node.NodePtr(), node().NodePtr())); + GetNodePtr(outer), GetNodePtr(outer.Value()))); } /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -387,9 +389,6 @@ template > class Events : public REACT_IMPL::EventStreamBase { -protected: - using BaseT = REACT_IMPL::EventStreamBase; - private: using NodeT = REACT_IMPL::EventStreamNode; using NodePtrT = std::shared_ptr; @@ -397,32 +396,45 @@ class Events : public REACT_IMPL::EventStreamBase public: using ValueT = E; + // Default ctor Events() = default; + + // Copy ctor Events(const Events&) = default; - Events& operator=(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; } - explicit Events(NodePtrT&& nodePtr) : - Events::EventStreamBase( std::move(nodePtr) ) - {} - bool Equals(const Events& other) const { - return Events::BaseT::Equals(other); + return Events::EventStreamBase::Equals(other); } bool IsValid() const { - return Events::BaseT::IsValid(); + return Events::EventStreamBase::IsValid(); + } + + void SetWeightHint(WeightHint weight) + { + Events::EventStreamBase::SetWeightHint(weight); } auto Tokenize() const @@ -461,9 +473,6 @@ template > class Events : public REACT_IMPL::EventStreamBase> { -protected: - using BaseT = REACT_IMPL::EventStreamBase>; - private: using NodeT = REACT_IMPL::EventStreamNode>; using NodePtrT = std::shared_ptr; @@ -471,32 +480,45 @@ class Events : public REACT_IMPL::EventStreamBase using NodePtrT = std::shared_ptr; public: + // Default ctor EventSource() = default; + + // Copy ctor EventSource(const EventSource&) = default; - EventSource& operator=(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 assignemnt + EventSource& operator=(const EventSource&) = default; + + // Move assignment EventSource& operator=(EventSource&& other) { EventSource::Events::operator=( std::move(other) ); return *this; } - explicit EventSource(NodePtrT&& nodePtr) : - EventSource::Events( std::move(nodePtr) ) - {} - // Explicit emit - void Emit(const E& e) const { EventSource::BaseT::emit(e); } - void Emit(E&& e) const { EventSource::BaseT::emit(std::move(e)); } + void Emit(const E& e) const { EventSource::EventStreamBase::emit(e); } + void Emit(E&& 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::BaseT::emit(Token::value); + EventSource::EventStreamBase::emit(Token::value); } // Function object style - void operator()(const E& e) const { EventSource::BaseT::emit(e); } - void operator()(E&& e) const { EventSource::BaseT::emit(std::move(e)); } + 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::BaseT::emit(Token::value); + EventSource::EventStreamBase::emit(Token::value); } // Stream style const EventSource& operator<<(const E& e) const { - EventSource::BaseT::emit(e); + EventSource::EventStreamBase::emit(e); return *this; } const EventSource& operator<<(E&& e) const { - EventSource::BaseT::emit(std::move(e)); + EventSource::EventStreamBase::emit(std::move(e)); return *this; } }; @@ -607,34 +637,42 @@ class EventSource : public Events> using NodePtrT = std::shared_ptr; public: + // Default ctor EventSource() = default; + + // Copy ctor EventSource(const EventSource&) = default; - EventSource& operator=(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 EventSource(NodePtrT&& nodePtr) : - EventSource::Events( std::move(nodePtr) ) - {} - // Explicit emit - void Emit(std::reference_wrapper e) const { EventSource::BaseT::emit(e); } + void Emit(std::reference_wrapper e) const { EventSource::EventStreamBase::emit(e); } // Function object style - void operator()(std::reference_wrapper e) const { EventSource::BaseT::emit(e); } + void operator()(std::reference_wrapper e) const { EventSource::EventStreamBase::emit(e); } // Stream style const EventSource& operator<<(std::reference_wrapper e) const { - EventSource::BaseT::emit(e); + EventSource::EventStreamBase::emit(e); return *this; } }; @@ -654,19 +692,33 @@ class TempEvents : public Events using NodeT = REACT_IMPL::EventOpNode; using NodePtrT = std::shared_ptr; -public: +public: + // Default ctor TempEvents() = default; + + // Copy ctor TempEvents(const TempEvents&) = default; - TempEvents& operator=(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()); diff --git a/include/react/Observer.h b/include/react/Observer.h index 5bcd9957..07d76c32 100644 --- a/include/react/Observer.h +++ b/include/react/Observer.h @@ -34,6 +34,7 @@ template class Events; using REACT_IMPL::ObserverAction; +using REACT_IMPL::WeightHint; /////////////////////////////////////////////////////////////////////////////////////////////////// /// Observer @@ -42,56 +43,70 @@ template class Observer { private: - using SubjectT = REACT_IMPL::NodeBasePtrT; - using NodeT = REACT_IMPL::IObserver; + using SubjectPtrT = std::shared_ptr>; + using NodeT = REACT_IMPL::ObserverNode; public: + // Default ctor Observer() : - nodePtr_( nullptr ) + nodePtr_( nullptr ), + subjectPtr_( nullptr ) {} - Observer(const Observer&) = delete; - Observer& operator=(const Observer&) = delete; - + // Move ctor Observer(Observer&& other) : nodePtr_( other.nodePtr_ ), - subject_( std::move(other.subject_) ) + subjectPtr_( std::move(other.subjectPtr_) ) { other.nodePtr_ = nullptr; + other.subjectPtr_.reset(); } + // Node ctor + Observer(NodeT* nodePtr, const SubjectPtrT& subjectPtr) : + nodePtr_( nodePtr ), + subjectPtr_( subjectPtr ) + {} + + // Move assignment Observer& operator=(Observer&& other) { nodePtr_ = other.nodePtr_; - subject_ = std::move(other.subject_); + subjectPtr_ = std::move(other.subjectPtr_); other.nodePtr_ = nullptr; + other.subjectPtr_.reset(); return *this; } - Observer(NodeT* nodePtr, const SubjectT& subject) : - nodePtr_( nodePtr ), - subject_( subject ) - {} + // Deleted copy ctor and assignment + Observer(const Observer&) = delete; + Observer& operator=(const Observer&) = delete; + + void Detach() + { + assert(IsValid()); + subjectPtr_->UnregisterObserver(nodePtr_); + } bool IsValid() const { return nodePtr_ != nullptr; } - void Detach() + void SetWeightHint(WeightHint weight) { - REACT_ASSERT(IsValid(), "Detach on invalid Observer."); - REACT_IMPL::DomainSpecificObserverRegistry::Instance().Unregister(nodePtr_); + assert(IsValid()); + nodePtr_->SetWeightHint(weight); } private: - // Ownership managed by registry - NodeT* nodePtr_; + // Owned by subject + NodeT* nodePtr_; // While the observer handle exists, the subject is not destroyed - SubjectT subject_; + SubjectPtrT subjectPtr_; }; /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -101,27 +116,40 @@ template class ScopedObserver { public: - ScopedObserver() = delete; - ScopedObserver(const ScopedObserver&) = delete; - ScopedObserver& operator=(const ScopedObserver&) = delete; - + // 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) { obs_ = std::move(other.obs_); } - ScopedObserver(Observer&& obs) : - obs_( std::move(obs) ) - {} + // Deleted default ctor, copy ctor and assignment + ScopedObserver() = delete; + ScopedObserver(const ScopedObserver&) = delete; + ScopedObserver& operator=(const ScopedObserver&) = delete; ~ScopedObserver() { - if (obs_.IsValid()) - obs_.Detach(); + obs_.Detach(); + } + + bool IsValid() const + { + return obs_.IsValid(); + } + + void SetWeightHint(WeightHint weight) + { + obs_.SetWeightHint(weight); } private: @@ -141,8 +169,8 @@ auto Observe(const Signal& subject, FIn&& func) -> Observer { using REACT_IMPL::IObserver; + using REACT_IMPL::ObserverNode; using REACT_IMPL::SignalObserverNode; - using REACT_IMPL::DomainSpecificObserverRegistry; using REACT_IMPL::AddDefaultReturnValueWrapper; using F = typename std::decay::type; @@ -157,13 +185,15 @@ auto Observe(const Signal& subject, FIn&& func) SignalObserverNode >::type; - std::unique_ptr obsPtr(new TNode( - subject.NodePtr(), std::forward(func))); - auto* rawObsPtr = DomainSpecificObserverRegistry::Instance() - .Register(std::move(obsPtr), subject.NodePtr().get()); + const auto& subjectPtr = GetNodePtr(subject); - return Observer( rawObsPtr, subject.NodePtr() ); + std::unique_ptr> nodePtr( new TNode(subjectPtr, std::forward(func)) ); + ObserverNode* rawNodePtr = nodePtr.get(); + + subjectPtr->RegisterObserver(std::move(nodePtr)); + + return Observer( rawNodePtr, subjectPtr ); } /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -179,8 +209,8 @@ auto Observe(const Events& subject, FIn&& func) -> Observer { using REACT_IMPL::IObserver; + using REACT_IMPL::ObserverNode; using REACT_IMPL::EventObserverNode; - using REACT_IMPL::DomainSpecificObserverRegistry; using REACT_IMPL::AddDefaultReturnValueWrapper; using F = typename std::decay::type; @@ -195,13 +225,14 @@ auto Observe(const Events& subject, FIn&& func) EventObserverNode >::type; - std::unique_ptr obsPtr(new TNode( - subject.NodePtr(), std::forward(func))); + const auto& subjectPtr = GetNodePtr(subject); + + std::unique_ptr> nodePtr( new TNode(subjectPtr, std::forward(func)) ); + ObserverNode* rawNodePtr = nodePtr.get(); - auto* rawObsPtr = DomainSpecificObserverRegistry::Instance() - .Register(std::move(obsPtr), subject.NodePtr().get()); + subjectPtr->RegisterObserver(std::move(nodePtr)); - return Observer(rawObsPtr, subject.NodePtr()); + return Observer( rawNodePtr, subjectPtr ); } /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -219,8 +250,8 @@ auto Observe(const Events& subject, -> Observer { using REACT_IMPL::IObserver; + using REACT_IMPL::ObserverNode; using REACT_IMPL::SyncedObserverNode; - using REACT_IMPL::DomainSpecificObserverRegistry; using REACT_IMPL::AddDefaultReturnValueWrapper; using F = typename std::decay::type; @@ -243,25 +274,27 @@ auto Observe(const Events& subject, {} auto operator()(const Signal& ... deps) - -> std::unique_ptr + -> ObserverNode* { - return std::unique_ptr( - new TNode( - MySubject.NodePtr(), std::forward(MyFunc), deps.NodePtr() ... )); + return new TNode( + GetNodePtr(MySubject), std::forward(MyFunc), GetNodePtr(deps) ... ); } const Events& MySubject; FIn MyFunc; }; - auto obsPtr = REACT_IMPL::apply( + const auto& subjectPtr = GetNodePtr(subject); + + std::unique_ptr> nodePtr( REACT_IMPL::apply( NodeBuilder_( subject, std::forward(func) ), - depPack.Data); + depPack.Data) ); + + ObserverNode* rawNodePtr = nodePtr.get(); - auto* rawObsPtr = DomainSpecificObserverRegistry::Instance() - .Register(std::move(obsPtr), subject.NodePtr().get()); + subjectPtr->RegisterObserver(std::move(nodePtr)); - return Observer(rawObsPtr, subject.NodePtr()); + return Observer( rawNodePtr, subjectPtr ); } /******************************************/ REACT_END /******************************************/ diff --git a/include/react/Reactor.h b/include/react/Reactor.h index eac2f93e..2149dcac 100644 --- a/include/react/Reactor.h +++ b/include/react/Reactor.h @@ -41,19 +41,19 @@ class Reactor template E& Await(const Events& evn) { - return node_.Await(evn.NodePtr()); + return node_.Await(GetNodePtr(evn)); } template void RepeatUntil(const Events& evn, F&& func) { - node_.RepeatUntil(evn.NodePtr(), std::forward(func)); + node_.RepeatUntil(GetNodePtr(evn), std::forward(func)); } template const S& Get(const Signal& sig) { - return node_.Get(sig.NodePtr()); + return node_.Get(GetNodePtr(sig)); } private: diff --git a/include/react/Signal.h b/include/react/Signal.h index d031a844..936874b4 100644 --- a/include/react/Signal.h +++ b/include/react/Signal.h @@ -9,6 +9,10 @@ #pragma once +#if _MSC_VER && !__INTEL_COMPILER + #pragma warning(disable : 4503) +#endif + #include "react/detail/Defs.h" #include @@ -80,7 +84,9 @@ template typename V, typename S = typename std::decay::type, class = typename std::enable_if< - ! IsReactive::value>::type + ! IsSignal::value>::type, + class = typename std::enable_if< + ! IsEvent::value>::type > auto MakeVar(V&& value) -> VarSignal @@ -157,7 +163,7 @@ auto MakeSignal(const Signal& arg, FIn&& func) { return TempSignal( std::make_shared>( - std::forward(func), arg.NodePtr())); + std::forward(func), GetNodePtr(arg))); } // Multiple args @@ -186,7 +192,7 @@ auto MakeSignal(const SignalPack& argPack, FIn&& func) { return TempSignal( std::make_shared>( - std::forward(MyFunc), args.NodePtr() ...)); + std::forward(MyFunc), GetNodePtr(args) ...)); } FIn MyFunc; @@ -223,7 +229,7 @@ auto operator op(const TSignal& arg) { \ return TempSignal( \ std::make_shared>( \ - F(), arg.NodePtr())); \ + F(), GetNodePtr(arg))); \ } \ \ template \ @@ -334,7 +340,7 @@ auto operator op(const TLeftSignal& lhs, const TRightSignal& rhs) { \ return TempSignal( \ std::make_shared>( \ - F(), lhs.NodePtr(), rhs.NodePtr())); \ + F(), GetNodePtr(lhs), GetNodePtr(rhs))); \ } \ \ template \ @@ -358,7 +364,7 @@ auto operator op(const TLeftSignal& lhs, TRightValIn&& rhs) { \ return TempSignal( \ std::make_shared>( \ - F( std::forward(rhs) ), lhs.NodePtr())); \ + F( std::forward(rhs) ), GetNodePtr(lhs))); \ } \ \ template \ @@ -382,7 +388,7 @@ auto operator op(TLeftValIn&& lhs, const TRightSignal& rhs) { \ return TempSignal( \ std::make_shared>( \ - F( std::forward(lhs) ), rhs.NodePtr())); \ + F( std::forward(lhs) ), GetNodePtr(rhs))); \ } \ template \ < \ @@ -425,7 +431,7 @@ auto operator op(TempSignal&& lhs, { \ return TempSignal( \ std::make_shared>( \ - F(), lhs.StealOp(), rhs.NodePtr())); \ + F(), lhs.StealOp(), GetNodePtr(rhs))); \ } \ \ template \ @@ -448,7 +454,7 @@ auto operator op(const TLeftSignal& lhs, TempSignal&& rhs) { \ return TempSignal( \ std::make_shared>( \ - F(), lhs.NodePtr(), rhs.StealOp())); \ + F(), GetNodePtr(lhs), rhs.StealOp())); \ } \ \ template \ @@ -587,12 +593,12 @@ template typename D, typename TInnerValue > -auto Flatten(const Signal>& node) +auto Flatten(const Signal>& outer) -> Signal { return Signal( std::make_shared, TInnerValue>>( - node.NodePtr(), node.Value().NodePtr())); + GetNodePtr(outer), GetNodePtr(outer.Value()))); } /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -605,9 +611,6 @@ template > class Signal : public REACT_IMPL::SignalBase { -protected: - using BaseT = REACT_IMPL::SignalBase; - private: using NodeT = REACT_IMPL::SignalNode; using NodePtrT = std::shared_ptr; @@ -615,40 +618,54 @@ class Signal : public REACT_IMPL::SignalBase public: using ValueT = S; + // Default ctor Signal() = default; + + // Copy ctor Signal(const Signal&) = default; - Signal& operator=(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; } - explicit Signal(NodePtrT&& nodePtr) : - Signal::SignalBase( std::move(nodePtr) ) - {} - - const S& Value() const { return Signal::BaseT::getValue(); } - const S& operator()() const { return Signal::BaseT::getValue(); } + const S& Value() const { return Signal::SignalBase::getValue(); } + const S& operator()() const { return Signal::SignalBase::getValue(); } bool Equals(const Signal& other) const { - return Signal::BaseT::Equals(other); + return Signal::SignalBase::Equals(other); } bool IsValid() const { - return Signal::BaseT::IsValid(); + return Signal::SignalBase::IsValid(); + } + + void SetWeightHint(WeightHint weight) + { + Signal::SignalBase::SetWeightHint(weight); } S Flatten() const { - static_assert(IsReactive::value, "Flatten requires a Signal value type."); + static_assert(IsSignal::value || IsEvent::value, + "Flatten requires a Signal or Events value type."); return REACT::Flatten(*this); } }; @@ -661,9 +678,6 @@ template > class Signal : public REACT_IMPL::SignalBase> { -protected: - using BaseT = REACT_IMPL::SignalBase>; - private: using NodeT = REACT_IMPL::SignalNode>; using NodePtrT = std::shared_ptr; @@ -671,35 +685,48 @@ class Signal : public REACT_IMPL::SignalBase> public: using ValueT = S; + // Default ctor Signal() = default; + + // Copy ctor Signal(const Signal&) = default; - Signal& operator=(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; } - explicit Signal(NodePtrT&& nodePtr) : - Signal::SignalBase( std::move(nodePtr) ) - {} - - const S& Value() const { return Signal::BaseT::getValue(); } - const S& operator()() const { return Signal::BaseT::getValue(); } + const S& Value() const { return Signal::SignalBase::getValue(); } + const S& operator()() const { return Signal::SignalBase::getValue(); } bool Equals(const Signal& other) const { - return Signal::BaseT::Equals(other); + return Signal::SignalBase::Equals(other); } bool IsValid() const { - return Signal::BaseT::IsValid(); + return Signal::SignalBase::IsValid(); + } + + void SetWeightHint(WeightHint weight) + { + Signal::SignalBase::SetWeightHint(weight); } }; @@ -718,50 +745,58 @@ class VarSignal : public Signal using NodePtrT = std::shared_ptr; public: + // Default ctor VarSignal() = default; + + // Copy ctor VarSignal(const VarSignal&) = default; - VarSignal& operator=(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) ); + VarSignal::SignalBase::operator=( std::move(other) ); return *this; } - explicit VarSignal(NodePtrT&& nodePtr) : - VarSignal::Signal( std::move(nodePtr) ) - {} - void Set(const S& newValue) const { - VarSignal::BaseT::setValue(newValue); + VarSignal::SignalBase::setValue(newValue); } void Set(S&& newValue) const { - VarSignal::BaseT::setValue(std::move(newValue)); + VarSignal::SignalBase::setValue(std::move(newValue)); } const VarSignal& operator<<=(const S& newValue) const { - VarSignal::BaseT::setValue(newValue); + VarSignal::SignalBase::setValue(newValue); return *this; } const VarSignal& operator<<=(S&& newValue) const { - VarSignal::BaseT::setValue(std::move(newValue)); + VarSignal::SignalBase::setValue(std::move(newValue)); return *this; } template void Modify(const F& func) const { - VarSignal::BaseT::modifyValue(func); + VarSignal::SignalBase::modifyValue(func); } }; @@ -780,32 +815,40 @@ class VarSignal : public Signal> public: using ValueT = S; + // Default ctor VarSignal() = default; + + // Copy ctor VarSignal(const VarSignal&) = default; - VarSignal& operator=(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; } - explicit VarSignal(NodePtrT&& nodePtr) : - VarSignal::Signal( std::move(nodePtr) ) - {} - void Set(std::reference_wrapper newValue) const { - VarSignal::BaseT::setValue(newValue); + VarSignal::SignalBase::setValue(newValue); } const VarSignal& operator<<=(std::reference_wrapper newValue) const { - VarSignal::BaseT::setValue(newValue); + VarSignal::SignalBase::setValue(newValue); return *this; } }; @@ -825,25 +868,33 @@ class TempSignal : public Signal using NodeT = REACT_IMPL::SignalOpNode; using NodePtrT = std::shared_ptr; -public: +public: + // Default ctor TempSignal() = default; + + // Copy ctor TempSignal(const TempSignal&) = default; - TempSignal& operator=(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; } - explicit TempSignal(NodePtrT&& ptr) : - TempSignal::Signal( std::move(ptr) ) - {} - TOp StealOp() { return std::move(reinterpret_cast(this->ptr_.get())->StealOp()); diff --git a/include/react/common/Timing.h b/include/react/common/Timing.h index 8c8b62a8..08f72892 100644 --- a/include/react/common/Timing.h +++ b/include/react/common/Timing.h @@ -66,6 +66,8 @@ class ConditionalTimer ScopedTimer(const ConditionalTimer&, const size_t& count); }; + void Reset(); + void ForceThresholdExceeded(bool isExceeded); bool IsThresholdExceeded() const; }; @@ -84,7 +86,9 @@ class ConditionalTimer ScopedTimer(const ConditionalTimer&, const size_t& count) {} }; - bool IsThresholdExceeded() const { return false; } + void Reset() {} + void ForceThresholdExceeded(bool isExceeded) {} + bool IsThresholdExceeded() const { return false; } }; // Enabled @@ -142,7 +146,7 @@ class ConditionalTimer durationUS.QuadPart *= 1000000; durationUS.QuadPart /= GetPerformanceFrequency().QuadPart; - parent_.isThresholdExceeded_ = durationUS.QuadPart > (threshold * count_); + parent_.isThresholdExceeded_ = (durationUS.QuadPart - (threshold * count_)) > 0; #else using std::chrono::duration_cast; using std::chrono::microseconds; @@ -168,6 +172,18 @@ class ConditionalTimer #endif } + void Reset() + { + shouldMeasure_ = true; + isThresholdExceeded_ = false; + } + + void ForceThresholdExceeded(bool isExceeded) + { + shouldMeasure_ = false; + isThresholdExceeded_ = isExceeded; + } + bool IsThresholdExceeded() const { return isThresholdExceeded_; } private: diff --git a/include/react/detail/DomainBase.h b/include/react/detail/DomainBase.h new file mode 100644 index 00000000..67c7e8ae --- /dev/null +++ b/include/react/detail/DomainBase.h @@ -0,0 +1,265 @@ + +// 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) + +#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 index 907365f6..583651aa 100644 --- a/include/react/detail/EventBase.h +++ b/include/react/detail/EventBase.h @@ -27,15 +27,15 @@ template typename D, typename E > -class EventStreamBase : public ReactiveBase> +class EventStreamBase : public CopyableReactive> { public: EventStreamBase() = default; EventStreamBase(const EventStreamBase&) = default; template - explicit EventStreamBase(T&& ptr) : - EventStreamBase::ReactiveBase( std::forward(ptr) ) + EventStreamBase(T&& t) : + EventStreamBase::CopyableReactive( std::forward(t) ) {} protected: diff --git a/include/react/detail/ObserverBase.h b/include/react/detail/ObserverBase.h index ec0f987f..814e0207 100644 --- a/include/react/detail/ObserverBase.h +++ b/include/react/detail/ObserverBase.h @@ -11,145 +11,67 @@ #include "react/detail/Defs.h" -#include #include -#include +#include #include #include "IReactiveNode.h" /***************************************/ REACT_IMPL_BEGIN /**************************************/ -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Forward declarations -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -class Observable; - /////////////////////////////////////////////////////////////////////////////////////////////////// /// IObserver /////////////////////////////////////////////////////////////////////////////////////////////////// class IObserver { public: - virtual ~IObserver() = default; + virtual ~IObserver() {} + + virtual void UnregisterSelf() = 0; private: virtual void detachObserver() = 0; template - friend class ObserverRegistry; + friend class Observable; }; /////////////////////////////////////////////////////////////////////////////////////////////////// -/// ObserverRegistry +/// Observable /////////////////////////////////////////////////////////////////////////////////////////////////// -// Todo: still ugly, needs more refactoring template -class ObserverRegistry +class Observable { -private: - class Entry - { - public: - Entry(std::unique_ptr&& nodePtr, const Observable* subjectPtr) : - SubjectPtr( subjectPtr ), - nodePtr_( std::move(nodePtr) ) - {} - - Entry(const Entry&) = delete; - - Entry(Entry&& other) : - SubjectPtr( other.SubjectPtr ), - nodePtr_( std::move(other.nodePtr_) ) - {} - - const Observable* SubjectPtr; - - private: - // Manage lifetime - std::unique_ptr nodePtr_; - }; - public: - // Pass ownership of obs node to registry - IObserver* Register(std::unique_ptr&& obsPtr, const Observable* subjectPtr) - { - // Use raw ptr copy as index to find owned version of itself - auto* rawObsPtr = obsPtr.get(); - - observerMap_.emplace(rawObsPtr, Entry( std::move(obsPtr), subjectPtr )); + Observable() = default; - return rawObsPtr; + ~Observable() + { + for (const auto& p : observers_) + if (p != nullptr) + p->detachObserver(); } - void Unregister(IObserver* obsPtr) + void RegisterObserver(std::unique_ptr&& obsPtr) { - obsPtr->detachObserver(); - observerMap_.erase(obsPtr); + observers_.push_back(std::move(obsPtr)); } - void UnregisterFrom(const Observable* subjectPtr) + void UnregisterObserver(IObserver* rawObsPtr) { - auto it = observerMap_.begin(); - while (it != observerMap_.end()) + for (auto it = observers_.begin(); it != observers_.end(); ++it) { - if (it->second.SubjectPtr == subjectPtr) + if (it->get() == rawObsPtr) { - it->first->detachObserver(); - it = observerMap_.erase(it); - } - else - { - ++it; + it->get()->detachObserver(); + observers_.erase(it); + break; } } } private: - std::unordered_map observerMap_; -}; - -template -class DomainSpecificObserverRegistry -{ -public: - DomainSpecificObserverRegistry() = delete; - - static ObserverRegistry& Instance() - { - static ObserverRegistry instance; - return instance; - } -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// Observable -/////////////////////////////////////////////////////////////////////////////////////////////////// -template -class Observable -{ -public: - Observable() : - obsCount_( 0u ) - {}; - - Observable(const Observable& other) : - obsCount_( other.GetObsCount() ) - {} - - void IncObsCount() { obsCount_.fetch_add(1, std::memory_order_relaxed); } - void DecObsCount() { obsCount_.fetch_sub(1, std::memory_order_relaxed); } - uint GetObsCount() const { return obsCount_.load(std::memory_order_relaxed); } - - ~Observable() - { - if (GetObsCount() > 0) - DomainSpecificObserverRegistry::Instance().UnregisterFrom(this); - } - -private: - std::atomic obsCount_; + std::vector> observers_; }; /****************************************/ REACT_IMPL_END /***************************************/ diff --git a/include/react/detail/ReactiveBase.h b/include/react/detail/ReactiveBase.h index da44e421..d7f32124 100644 --- a/include/react/detail/ReactiveBase.h +++ b/include/react/detail/ReactiveBase.h @@ -31,56 +31,128 @@ bool Equals(const std::reference_wrapper& lhs, const std::reference_wrapper class ReactiveBase { public: using DomainT = typename TNode::DomainT; - using NodePtrT = std::shared_ptr; - + + // Default ctor ReactiveBase() = default; + + // Copy ctor ReactiveBase(const ReactiveBase&) = default; - ReactiveBase& operator=(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; } - explicit ReactiveBase(const NodePtrT& ptr) : - ptr_( ptr ) + 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 ReactiveBase(NodePtrT&& ptr) : - ptr_( std::move(ptr) ) + explicit CopyableReactive(std::shared_ptr&& ptr) : + CopyableReactive::ReactiveBase( std::move(ptr) ) {} - const std::shared_ptr& NodePtr() const + CopyableReactive& operator=(const CopyableReactive&) = default; + + CopyableReactive& operator=(CopyableReactive&& other) { - return ptr_; + CopyableReactive::ReactiveBase::operator=(std::move(other)); + return *this; } - bool Equals(const ReactiveBase& other) const + bool Equals(const CopyableReactive& other) const { - return ptr_ == other.ptr_; + return this->ptr_ == other.ptr_; } +}; - bool IsValid() const +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// 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) { - return ptr_ != nullptr; + MovableReactive::ReactiveBase::operator=(std::move(other)); + return *this; } -protected: - std::shared_ptr ptr_; + // 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 906e6e0f..fb2ceaf2 100644 --- a/include/react/detail/ReactiveInput.h +++ b/include/react/detail/ReactiveInput.h @@ -151,10 +151,8 @@ class ContinuationManager template void DetachQueuedObservers() { - auto& registry = DomainSpecificObserverRegistry::Instance(); - for (auto* o : detachedObservers_) - registry.Unregister(o); + o->UnregisterSelf(); detachedObservers_.clear(); } @@ -214,12 +212,10 @@ class ContinuationManager template void DetachQueuedObservers() { - auto& registry = DomainSpecificObserverRegistry::Instance(); - for (auto& v : detachedObservers_) { for (auto* o : v) - registry.Unregister(o); + o->UnregisterSelf(); v.clear(); } } diff --git a/include/react/detail/SignalBase.h b/include/react/detail/SignalBase.h index 3ba0abb8..6c41b9df 100644 --- a/include/react/detail/SignalBase.h +++ b/include/react/detail/SignalBase.h @@ -27,15 +27,15 @@ template typename D, typename S > -class SignalBase : public ReactiveBase> +class SignalBase : public CopyableReactive> { public: SignalBase() = default; SignalBase(const SignalBase&) = default; template - explicit SignalBase(T&& ptr) : - SignalBase::ReactiveBase( std::forward(ptr) ) + SignalBase(T&& t) : + SignalBase::CopyableReactive( std::forward(t) ) {} protected: diff --git a/include/react/detail/graph/AlgorithmNodes.h b/include/react/detail/graph/AlgorithmNodes.h index d3559e27..fc89aaf9 100644 --- a/include/react/detail/graph/AlgorithmNodes.h +++ b/include/react/detail/graph/AlgorithmNodes.h @@ -30,8 +30,7 @@ template typename TFunc > class IterateNode : - public SignalNode, - public UpdateTimingPolicy + public SignalNode { using Engine = typename IterateNode::Engine; @@ -90,11 +89,6 @@ class IterateNode : virtual const char* GetNodeType() const override { return "IterateNode"; } virtual int DependencyCount() const override { return 1; } - virtual bool IsHeavyweight() const override - { - return this->IsUpdateThresholdExceeded(); - } - private: std::shared_ptr> events_; @@ -112,8 +106,7 @@ template typename TFunc > class IterateByRefNode : - public SignalNode, - public UpdateTimingPolicy + public SignalNode { using Engine = typename IterateByRefNode::Engine; @@ -160,11 +153,6 @@ class IterateByRefNode : virtual const char* GetNodeType() const override { return "IterateByRefNode"; } virtual int DependencyCount() const override { return 1; } - virtual bool IsHeavyweight() const override - { - return this->IsUpdateThresholdExceeded(); - } - protected: TFunc func_; @@ -183,8 +171,7 @@ template typename ... TDepValues > class SyncedIterateNode : - public SignalNode, - public UpdateTimingPolicy + public SignalNode { using Engine = typename SyncedIterateNode::Engine; @@ -273,11 +260,6 @@ class SyncedIterateNode : virtual const char* GetNodeType() const override { return "SyncedIterateNode"; } virtual int DependencyCount() const override { return 1 + sizeof...(TDepValues); } - virtual bool IsHeavyweight() const override - { - return this->IsUpdateThresholdExceeded(); - } - private: using DepHolderT = std::tuple>...>; @@ -299,8 +281,7 @@ template typename ... TDepValues > class SyncedIterateByRefNode : - public SignalNode, - public UpdateTimingPolicy + public SignalNode { using Engine = typename SyncedIterateByRefNode::Engine; @@ -383,11 +364,6 @@ class SyncedIterateByRefNode : virtual const char* GetNodeType() const override { return "SyncedIterateByRefNode"; } virtual int DependencyCount() const override { return 1 + sizeof...(TDepValues); } - virtual bool IsHeavyweight() const override - { - return this->IsUpdateThresholdExceeded(); - } - private: using DepHolderT = std::tuple>...>; diff --git a/include/react/detail/graph/ContinuationNodes.h b/include/react/detail/graph/ContinuationNodes.h index 85cfa5be..ab3c3cd2 100644 --- a/include/react/detail/graph/ContinuationNodes.h +++ b/include/react/detail/graph/ContinuationNodes.h @@ -34,8 +34,7 @@ class EventStreamNode; /// ContinuationNode /////////////////////////////////////////////////////////////////////////////////////////////////// template -class ContinuationNode : - public ReactiveNode +class ContinuationNode : public NodeBase { public: ContinuationNode(TransactionFlagsT turnFlags) : diff --git a/include/react/detail/graph/EventNodes.h b/include/react/detail/graph/EventNodes.h index 8c8688e2..484ed997 100644 --- a/include/react/detail/graph/EventNodes.h +++ b/include/react/detail/graph/EventNodes.h @@ -53,7 +53,7 @@ template typename E > class EventStreamNode : - public ReactiveNode, + public ObservableNode, private BufferClearAccessPolicy { public: @@ -385,8 +385,7 @@ template typename TOp > class EventOpNode : - public EventStreamNode, - public UpdateTimingPolicy + public EventStreamNode { using Engine = typename EventOpNode::Engine; @@ -441,11 +440,6 @@ class EventOpNode : virtual const char* GetNodeType() const override { return "EventOpNode"; } virtual int DependencyCount() const override { return TOp::dependency_count; } - virtual bool IsHeavyweight() const override - { - return this->IsUpdateThresholdExceeded(); - } - TOp StealOp() { REACT_ASSERT(wasOpStolen_ == false, "Op was already stolen."); @@ -514,7 +508,7 @@ class EventFlattenNode : public EventStreamNode this->SetCurrentTurn(turn, true); inner_->SetCurrentTurn(turn); - auto newInner = outer_->ValueRef().NodePtr(); + auto newInner = GetNodePtr(outer_->ValueRef()); if (newInner != inner_) { @@ -564,8 +558,7 @@ template typename ... TDepValues > class SyncedEventTransformNode : - public EventStreamNode, - public UpdateTimingPolicy + public EventStreamNode { using Engine = typename SyncedEventTransformNode::Engine; @@ -644,11 +637,6 @@ class SyncedEventTransformNode : virtual const char* GetNodeType() const override { return "SyncedEventTransformNode"; } virtual int DependencyCount() const override { return 1 + sizeof...(TDepValues); } - virtual bool IsHeavyweight() const override - { - return this->IsUpdateThresholdExceeded(); - } - private: using DepHolderT = std::tuple>...>; @@ -669,8 +657,7 @@ template typename ... TDepValues > class SyncedEventFilterNode : - public EventStreamNode, - public UpdateTimingPolicy + public EventStreamNode { using Engine = typename SyncedEventFilterNode::Engine; diff --git a/include/react/detail/graph/GraphBase.h b/include/react/detail/graph/GraphBase.h index a8d1d1ad..29382e82 100644 --- a/include/react/detail/graph/GraphBase.h +++ b/include/react/detail/graph/GraphBase.h @@ -22,6 +22,16 @@ /***************************************/ REACT_IMPL_BEGIN /**************************************/ +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// UpdateTimingPolicy +/////////////////////////////////////////////////////////////////////////////////////////////////// +enum class WeightHint +{ + automatic, + light, + heavy +}; + /////////////////////////////////////////////////////////////////////////////////////////////////// /// UpdateTimingPolicy /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -44,7 +54,9 @@ class UpdateTimingPolicy : {} }; - bool IsUpdateThresholdExceeded() const { return this->IsThresholdExceeded(); } + void ResetUpdateThreshold() { this->Reset(); } + void ForceUpdateThresholdExceeded(bool v) { this->ForceThresholdExceeded(v); } + bool IsUpdateThresholdExceeded() const { return this->IsThresholdExceeded(); } }; /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -76,7 +88,7 @@ template class NodeBase : public std::enable_shared_from_this>, public D::Policy::Engine::NodeT, - public Observable + public UpdateTimingPolicy { public: using DomainT = D; @@ -84,11 +96,33 @@ class NodeBase : using Engine = typename D::Engine; using NodeT = typename Engine::NodeT; using TurnT = typename Engine::TurnT; + + NodeBase() = default; + + // Nodes can't be copied + NodeBase(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 IsHeavyweight() const override { return false; } + + virtual bool IsHeavyweight() const override { return this->IsUpdateThresholdExceeded(); } + + void SetWeightHint(WeightHint weight) + { + switch (weight) + { + case WeightHint::heavy : + this->ForceUpdateThresholdExceeded(true); + break; + case WeightHint::light : + this->ForceUpdateThresholdExceeded(false); + break; + case WeightHint::automatic : + this->ResetUpdateThreshold(); + break; + } + } std::shared_ptr GetSharedPtr() const { @@ -100,21 +134,15 @@ template using NodeBasePtrT = std::shared_ptr>; /////////////////////////////////////////////////////////////////////////////////////////////////// -/// ReactiveNode +/// ObservableNode /////////////////////////////////////////////////////////////////////////////////////////////////// -template -< - typename D, - typename P, - typename V -> -class ReactiveNode : public NodeBase +template +class ObservableNode : + public NodeBase, + public Observable { public: - ReactiveNode() = default; - - // Reactive nodes can't be copied - ReactiveNode(const ReactiveNode&) = delete; + ObservableNode() = default; }; /////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/include/react/detail/graph/ObserverNodes.h b/include/react/detail/graph/ObserverNodes.h index 2def3890..a2d4c1df 100644 --- a/include/react/detail/graph/ObserverNodes.h +++ b/include/react/detail/graph/ObserverNodes.h @@ -43,7 +43,7 @@ enum class ObserverAction /////////////////////////////////////////////////////////////////////////////////////////////////// template class ObserverNode : - public ReactiveNode, + public NodeBase, public IObserver { public: @@ -62,8 +62,7 @@ template typename TFunc > class SignalObserverNode : - public ObserverNode, - public UpdateTimingPolicy + public ObserverNode { using Engine = typename SignalObserverNode::Engine; @@ -75,7 +74,6 @@ class SignalObserverNode : func_( std::forward(func) ) { Engine::OnNodeCreate(*this); - subject->IncObsCount(); Engine::OnNodeAttach(*this, *subject); } @@ -116,13 +114,17 @@ class SignalObserverNode : GetObjectId(*this), turn.Id())); } + virtual void UnregisterSelf() override + { + if (auto p = subject_.lock()) + p->UnregisterObserver(this); + } + private: virtual void detachObserver() override { if (auto p = subject_.lock()) { - p->DecObsCount(); - Engine::OnNodeDetach(*this, *p); subject_.reset(); } @@ -142,8 +144,7 @@ template typename TFunc > class EventObserverNode : - public ObserverNode, - public UpdateTimingPolicy + public ObserverNode { using Engine = typename EventObserverNode::Engine; @@ -155,7 +156,6 @@ class EventObserverNode : func_( std::forward(func) ) { Engine::OnNodeCreate(*this); - subject->IncObsCount(); Engine::OnNodeAttach(*this, *subject); } @@ -202,6 +202,12 @@ class EventObserverNode : GetObjectId(*this), turn.Id())); } + virtual void UnregisterSelf() override + { + if (auto p = subject_.lock()) + p->UnregisterObserver(this); + } + private: std::weak_ptr> subject_; @@ -211,8 +217,6 @@ class EventObserverNode : { if (auto p = subject_.lock()) { - p->DecObsCount(); - Engine::OnNodeDetach(*this, *p); subject_.reset(); } @@ -230,13 +234,11 @@ template typename ... TDepValues > class SyncedObserverNode : - public ObserverNode, - public UpdateTimingPolicy + public ObserverNode { using Engine = typename SyncedObserverNode::Engine; public: - // NOTE: After upgrading to VS2013 Udpate2, using std::shared_ptr here crashes the compiler template SyncedObserverNode(const std::shared_ptr>& subject, F&& func, const std::shared_ptr>& ... deps) : @@ -246,7 +248,6 @@ class SyncedObserverNode : deps_( deps ... ) { Engine::OnNodeCreate(*this); - subject->IncObsCount(); Engine::OnNodeAttach(*this, *subject); REACT_EXPAND_PACK(Engine::OnNodeAttach(*this, *deps)); @@ -315,6 +316,12 @@ class SyncedObserverNode : GetObjectId(*this), turn.Id())); } + virtual void UnregisterSelf() override + { + if (auto p = subject_.lock()) + p->UnregisterObserver(this); + } + private: using DepHolderT = std::tuple>...>; @@ -327,8 +334,6 @@ class SyncedObserverNode : { if (auto p = subject_.lock()) { - p->DecObsCount(); - Engine::OnNodeDetach(*this, *p); apply( diff --git a/include/react/detail/graph/ReactorNodes.h b/include/react/detail/graph/ReactorNodes.h index 9a259bae..b693a5f0 100644 --- a/include/react/detail/graph/ReactorNodes.h +++ b/include/react/detail/graph/ReactorNodes.h @@ -34,7 +34,7 @@ template typename TContext > class ReactorNode : - public ReactiveNode + public NodeBase { using Engine = typename ReactorNode::Engine; @@ -46,7 +46,7 @@ class ReactorNode : template ReactorNode(F&& func) : - ReactorNode::ReactiveNode( ), + ReactorNode::NodeBase( ), func_( std::forward(func) ) { Engine::OnNodeCreate(*this); diff --git a/include/react/detail/graph/SignalNodes.h b/include/react/detail/graph/SignalNodes.h index 7715cff2..eb438a0c 100644 --- a/include/react/detail/graph/SignalNodes.h +++ b/include/react/detail/graph/SignalNodes.h @@ -32,14 +32,14 @@ template typename D, typename S > -class SignalNode : public ReactiveNode +class SignalNode : public ObservableNode { public: SignalNode() = default; template explicit SignalNode(T&& value) : - SignalNode::ReactiveNode( ), + SignalNode::ObservableNode( ), value_( std::forward(value) ) {} @@ -233,8 +233,7 @@ template typename TOp > class SignalOpNode : - public SignalNode, - public UpdateTimingPolicy + public SignalNode { using Engine = typename SignalOpNode::Engine; @@ -292,11 +291,6 @@ class SignalOpNode : virtual const char* GetNodeType() const override { return "SignalOpNode"; } virtual int DependencyCount() const override { return TOp::dependency_count; } - virtual bool IsHeavyweight() const override - { - return this->IsUpdateThresholdExceeded(); - } - TOp StealOp() { REACT_ASSERT(wasOpStolen_ == false, "Op was already stolen."); @@ -347,7 +341,7 @@ class FlattenNode : public SignalNode using TurnT = typename D::Engine::TurnT; TurnT& turn = *reinterpret_cast(turnPtr); - auto newInner = outer_->ValueRef().NodePtr(); + auto newInner = GetNodePtr(outer_->ValueRef()); if (newInner != inner_) { diff --git a/project/msvc/CppReact.vcxproj.filters b/project/msvc/CppReact.vcxproj.filters index cf59babe..7de3201b 100644 --- a/project/msvc/CppReact.vcxproj.filters +++ b/project/msvc/CppReact.vcxproj.filters @@ -147,6 +147,9 @@ Header Files\common + + Header Files\detail + From 8fa654bd3379220de29ba0b424dff8b00e22212c Mon Sep 17 00:00:00 2001 From: schlangster Date: Tue, 29 Jul 2014 03:05:54 +0200 Subject: [PATCH 06/86] Added rudimentary test case for SetWeightHint. --- project/msvc/CppReactTest.vcxproj | 2 + project/msvc/CppReactTest.vcxproj.filters | 6 +++ tests/src/ParallelizationTest.cpp | 29 +++++++++++ tests/src/ParallelizationTest.h | 63 +++++++++++++++++++++++ 4 files changed, 100 insertions(+) create mode 100644 tests/src/ParallelizationTest.cpp create mode 100644 tests/src/ParallelizationTest.h diff --git a/project/msvc/CppReactTest.vcxproj b/project/msvc/CppReactTest.vcxproj index ff65e1d5..7b1cb65f 100644 --- a/project/msvc/CppReactTest.vcxproj +++ b/project/msvc/CppReactTest.vcxproj @@ -174,6 +174,7 @@ + @@ -183,6 +184,7 @@ + diff --git a/project/msvc/CppReactTest.vcxproj.filters b/project/msvc/CppReactTest.vcxproj.filters index 91914d7c..ae74e006 100644 --- a/project/msvc/CppReactTest.vcxproj.filters +++ b/project/msvc/CppReactTest.vcxproj.filters @@ -45,6 +45,9 @@ Source Files + + Source Files + @@ -68,5 +71,8 @@ Header Files + + Header Files + \ No newline at end of file diff --git a/tests/src/ParallelizationTest.cpp b/tests/src/ParallelizationTest.cpp new file mode 100644 index 00000000..aa583c17 --- /dev/null +++ b/tests/src/ParallelizationTest.cpp @@ -0,0 +1,29 @@ + +// 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 "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 new file mode 100644 index 00000000..6c5fd1d7 --- /dev/null +++ b/tests/src/ParallelizationTest.h @@ -0,0 +1,63 @@ + +// 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) + +#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 From e35720f24527967fbca005ee47c9399e8c5de233 Mon Sep 17 00:00:00 2001 From: schlangster Date: Tue, 29 Jul 2014 14:19:26 +0200 Subject: [PATCH 07/86] Cleanup. --- include/react/detail/graph/GraphBase.h | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/include/react/detail/graph/GraphBase.h b/include/react/detail/graph/GraphBase.h index 29382e82..38979813 100644 --- a/include/react/detail/graph/GraphBase.h +++ b/include/react/detail/graph/GraphBase.h @@ -23,7 +23,7 @@ /***************************************/ REACT_IMPL_BEGIN /**************************************/ /////////////////////////////////////////////////////////////////////////////////////////////////// -/// UpdateTimingPolicy +/// WeightHint /////////////////////////////////////////////////////////////////////////////////////////////////// enum class WeightHint { @@ -86,7 +86,6 @@ struct DepCounter /////////////////////////////////////////////////////////////////////////////////////////////////// template class NodeBase : - public std::enable_shared_from_this>, public D::Policy::Engine::NodeT, public UpdateTimingPolicy { @@ -123,11 +122,6 @@ class NodeBase : break; } } - - std::shared_ptr GetSharedPtr() const - { - return this->shared_from_this(); - } }; template From 39b10515137dc6430d36ee723bc60374104ef7aa Mon Sep 17 00:00:00 2001 From: schlangster Date: Tue, 29 Jul 2014 14:20:54 +0200 Subject: [PATCH 08/86] Added AsyncTransaction example. --- examples/src/BasicSynchronization.cpp | 165 ++++++++++++++++++ include/react/detail/ReactiveInput.h | 3 +- .../msvc/Example_BasicSynchronization.vcxproj | 2 + 3 files changed, 169 insertions(+), 1 deletion(-) diff --git a/examples/src/BasicSynchronization.cpp b/examples/src/BasicSynchronization.cpp index e27d1a93..38f05f3e 100644 --- a/examples/src/BasicSynchronization.cpp +++ b/examples/src/BasicSynchronization.cpp @@ -1,5 +1,170 @@ +// 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 "tbb/tick_count.h" + +#include "react/Domain.h" +#include "react/Event.h" +#include "react/Observer.h" + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// Example 1 - Asynchronous transactions +/////////////////////////////////////////////////////////////////////////////////////////////////// +namespace example1 +{ + using namespace react; + using namespace std; + + REACTIVE_DOMAIN(D, sequential_concurrent) + + class Sensor + { + public: + USING_REACTIVE_DOMAIN(D) + + EventSourceT Samples = MakeEventSource(); + }; + + void Run() + { + cout << "Example 1 - Asynchronous transactions" << endl; + + Sensor mySensor; + + Observe(mySensor.Samples, [] (int v) { + cout << v << std::endl; + }); + + TransactionStatus status; + + AsyncTransaction(status, [&] { + mySensor.Samples << 30 << 31 << 31 << 32; + }); + + AsyncTransaction(status, [&] { + mySensor.Samples << 40 << 41 << 51 << 62; + }); + + // Waits until both transactions are completed. + // This does not mean that both transactions are interleaved. + status.Wait(); + + cout << endl; + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// Example 2 - Transaction merging +/////////////////////////////////////////////////////////////////////////////////////////////////// +namespace example2 +{ + using namespace react; + using namespace std; + + REACTIVE_DOMAIN(D, sequential_concurrent) + + class Sensor + { + public: + USING_REACTIVE_DOMAIN(D) + + EventSourceT Samples = MakeEventSource(); + }; + + const int K = 100000; + + namespace v1 + { + void Run() + { + cout << "Example 2 - Transaction merging (no merging)" << endl; + + Sensor mySensor; + int sum = 0; + + Observe(mySensor.Samples, [&] (int v) { + sum += v; + }); + + TransactionStatus status; + + cout << "Executing " << K << " async transactions..."; + + auto t0 = tbb::tick_count::now(); + + for (int i=0; i < K; i++) + { + AsyncTransaction(status, [&] { + mySensor.Samples << 3 << 4 << 2 << 1; + }); + } + + status.Wait(); + + double d = (tbb::tick_count::now() - t0).seconds(); + + cout << " done." << endl; + + cout << " Sum: " << sum << endl; + cout << " Time: " << d << endl; + + cout << endl; + } + } + + namespace v2 + { + void Run() + { + cout << "Example 2 - Transaction merging (allow merging)" << endl; + + Sensor mySensor; + int sum = 0; + + Observe(mySensor.Samples, [&] (int v) { + sum += v; + }); + + TransactionStatus status; + + cout << "Executing " << K << " async transactions..."; + + auto t0 = tbb::tick_count::now(); + + for (int i=0; i < K; i++) + { + AsyncTransaction(allow_merging, status, [&] { + mySensor.Samples << 3 << 4 << 2 << 1; + }); + } + + status.Wait(); + + double d = (tbb::tick_count::now() - t0).seconds(); + + cout << " done." << endl; + + cout << " Sum: " << sum << endl; + cout << " Time: " << d << endl; + + cout << endl; + } + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// Run examples +/////////////////////////////////////////////////////////////////////////////////////////////////// int main() { + example1::Run(); + example2::v1::Run(); + example2::v2::Run(); + + return 0; } \ No newline at end of file diff --git a/include/react/detail/ReactiveInput.h b/include/react/detail/ReactiveInput.h index fb2ceaf2..dbab6b1f 100644 --- a/include/react/detail/ReactiveInput.h +++ b/include/react/detail/ReactiveInput.h @@ -744,7 +744,8 @@ class InputManager : if (canMerge) { uint extraCount = 0; - while (extraCount < 100 && asyncQueue_.try_pop(item)) + // Todo: Make configurable + while (extraCount < 512 && asyncQueue_.try_pop(item)) { bool canMergeNext = (item.Flags & allow_merging) != 0; if (canMergeNext) diff --git a/project/msvc/Example_BasicSynchronization.vcxproj b/project/msvc/Example_BasicSynchronization.vcxproj index 919643b3..2b2edec4 100644 --- a/project/msvc/Example_BasicSynchronization.vcxproj +++ b/project/msvc/Example_BasicSynchronization.vcxproj @@ -118,6 +118,7 @@ true true true + Console @@ -133,6 +134,7 @@ true true true + Console From d20d972731d30e73fa6ae8e51b8820167f7149e5 Mon Sep 17 00:00:00 2001 From: schlangster Date: Tue, 29 Jul 2014 14:21:22 +0200 Subject: [PATCH 09/86] Cleanup. --- include/react/Domain.h | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/include/react/Domain.h b/include/react/Domain.h index 548560a2..1279c3f9 100644 --- a/include/react/Domain.h +++ b/include/react/Domain.h @@ -96,19 +96,19 @@ class TransactionStatus using PtrT = REACT_IMPL::WaitingStatePtrT; public: + // Default ctor inline TransactionStatus() : statePtr_( StateT::Create() ) {} - TransactionStatus(const TransactionStatus&) = delete; - TransactionStatus& operator=(const TransactionStatus&) = delete; - + // Move ctor inline TransactionStatus(TransactionStatus&& other) : statePtr_( std::move(other.statePtr_) ) { other.statePtr_ = StateT::Create(); } + // Move assignment inline TransactionStatus& operator=(TransactionStatus&& other) { if (this != &other) @@ -119,6 +119,10 @@ class TransactionStatus return *this; } + // Deleted copy ctor & assignment + TransactionStatus(const TransactionStatus&) = delete; + TransactionStatus& operator=(const TransactionStatus&) = delete; + inline void Wait() { assert(statePtr_.Get() != nullptr); @@ -152,21 +156,29 @@ class Continuation : public REACT_IMPL::ContinuationBase 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; }; /////////////////////////////////////////////////////////////////////////////////////////////////// From cd4801890ac75a5170c191bf776ed61e503646c3 Mon Sep 17 00:00:00 2001 From: schlangster Date: Tue, 29 Jul 2014 20:03:04 +0200 Subject: [PATCH 10/86] Removed images from main source tree. They will be moved to the gh-pages branch, where they belong. --- doc/media/graphs/flow_eventflatten.graphml | 149 ------ doc/media/graphs/flow_eventflatten.png | Bin 5218 -> 0 bytes doc/media/graphs/flow_filter.graphml | 110 ---- doc/media/graphs/flow_filter.png | Bin 4369 -> 0 bytes doc/media/graphs/flow_filter2.graphml | 197 ------- doc/media/graphs/flow_filter2.png | Bin 8051 -> 0 bytes doc/media/graphs/flow_flatten.graphml | 149 ------ doc/media/graphs/flow_flatten.png | Bin 4622 -> 0 bytes doc/media/graphs/flow_hold.graphml | 111 ---- doc/media/graphs/flow_hold.png | Bin 4216 -> 0 bytes doc/media/graphs/flow_iterate.graphml | 111 ---- doc/media/graphs/flow_iterate.png | Bin 4677 -> 0 bytes doc/media/graphs/flow_iterate2.graphml | 198 ------- doc/media/graphs/flow_iterate2.png | Bin 8052 -> 0 bytes doc/media/graphs/flow_makesignal.graphml | 206 -------- doc/media/graphs/flow_makesignal.png | Bin 6945 -> 0 bytes doc/media/graphs/flow_makesource.graphml | 109 ---- doc/media/graphs/flow_makesource.png | Bin 1521 -> 0 bytes doc/media/graphs/flow_makevar.graphml | 111 ---- doc/media/graphs/flow_makevar.png | Bin 1675 -> 0 bytes doc/media/graphs/flow_merge.graphml | 205 -------- doc/media/graphs/flow_merge.png | Bin 7452 -> 0 bytes doc/media/graphs/flow_monitor.graphml | 110 ---- doc/media/graphs/flow_monitor.png | Bin 3515 -> 0 bytes doc/media/graphs/flow_observe.graphml | 109 ---- doc/media/graphs/flow_observe.png | Bin 4412 -> 0 bytes doc/media/graphs/flow_observe2.graphml | 109 ---- doc/media/graphs/flow_observe2.png | Bin 3987 -> 0 bytes doc/media/graphs/flow_observe3.graphml | 196 ------- doc/media/graphs/flow_observe3.png | Bin 8143 -> 0 bytes doc/media/graphs/flow_pulse.graphml | 141 ----- doc/media/graphs/flow_pulse.png | Bin 5700 -> 0 bytes doc/media/graphs/flow_snapshot.graphml | 142 ----- doc/media/graphs/flow_snapshot.png | Bin 5731 -> 0 bytes doc/media/graphs/flow_transform.graphml | 110 ---- doc/media/graphs/flow_transform.png | Bin 4321 -> 0 bytes doc/media/graphs/flow_transform2.graphml | 197 ------- doc/media/graphs/flow_transform2.png | Bin 7915 -> 0 bytes doc/media/helloworld.graphml | 222 -------- doc/media/helloworld.png | Bin 7126 -> 0 bytes doc/media/reactives1.graphml | 178 ------- doc/media/reactives2.graphml | 358 ------------- doc/media/signals1.graphml | 178 ------- doc/media/signals1.png | Bin 3869 -> 0 bytes doc/media/signals2.graphml | 358 ------------- doc/media/signals2.png | Bin 9576 -> 0 bytes doc/media/toposort1.graphml | 579 --------------------- doc/media/toposort1.png | Bin 25492 -> 0 bytes doc/media/toposort2.graphml | 570 -------------------- doc/media/toposort2.png | Bin 10369 -> 0 bytes doc/media/toposort3.graphml | 156 ------ doc/media/toposort3.png | Bin 7912 -> 0 bytes 52 files changed, 5369 deletions(-) delete mode 100644 doc/media/graphs/flow_eventflatten.graphml delete mode 100644 doc/media/graphs/flow_eventflatten.png delete mode 100644 doc/media/graphs/flow_filter.graphml delete mode 100644 doc/media/graphs/flow_filter.png delete mode 100644 doc/media/graphs/flow_filter2.graphml delete mode 100644 doc/media/graphs/flow_filter2.png delete mode 100644 doc/media/graphs/flow_flatten.graphml delete mode 100644 doc/media/graphs/flow_flatten.png delete mode 100644 doc/media/graphs/flow_hold.graphml delete mode 100644 doc/media/graphs/flow_hold.png delete mode 100644 doc/media/graphs/flow_iterate.graphml delete mode 100644 doc/media/graphs/flow_iterate.png delete mode 100644 doc/media/graphs/flow_iterate2.graphml delete mode 100644 doc/media/graphs/flow_iterate2.png delete mode 100644 doc/media/graphs/flow_makesignal.graphml delete mode 100644 doc/media/graphs/flow_makesignal.png delete mode 100644 doc/media/graphs/flow_makesource.graphml delete mode 100644 doc/media/graphs/flow_makesource.png delete mode 100644 doc/media/graphs/flow_makevar.graphml delete mode 100644 doc/media/graphs/flow_makevar.png delete mode 100644 doc/media/graphs/flow_merge.graphml delete mode 100644 doc/media/graphs/flow_merge.png delete mode 100644 doc/media/graphs/flow_monitor.graphml delete mode 100644 doc/media/graphs/flow_monitor.png delete mode 100644 doc/media/graphs/flow_observe.graphml delete mode 100644 doc/media/graphs/flow_observe.png delete mode 100644 doc/media/graphs/flow_observe2.graphml delete mode 100644 doc/media/graphs/flow_observe2.png delete mode 100644 doc/media/graphs/flow_observe3.graphml delete mode 100644 doc/media/graphs/flow_observe3.png delete mode 100644 doc/media/graphs/flow_pulse.graphml delete mode 100644 doc/media/graphs/flow_pulse.png delete mode 100644 doc/media/graphs/flow_snapshot.graphml delete mode 100644 doc/media/graphs/flow_snapshot.png delete mode 100644 doc/media/graphs/flow_transform.graphml delete mode 100644 doc/media/graphs/flow_transform.png delete mode 100644 doc/media/graphs/flow_transform2.graphml delete mode 100644 doc/media/graphs/flow_transform2.png delete mode 100644 doc/media/helloworld.graphml delete mode 100644 doc/media/helloworld.png delete mode 100644 doc/media/reactives1.graphml delete mode 100644 doc/media/reactives2.graphml delete mode 100644 doc/media/signals1.graphml delete mode 100644 doc/media/signals1.png delete mode 100644 doc/media/signals2.graphml delete mode 100644 doc/media/signals2.png delete mode 100644 doc/media/toposort1.graphml delete mode 100644 doc/media/toposort1.png delete mode 100644 doc/media/toposort2.graphml delete mode 100644 doc/media/toposort2.png delete mode 100644 doc/media/toposort3.graphml delete mode 100644 doc/media/toposort3.png diff --git a/doc/media/graphs/flow_eventflatten.graphml b/doc/media/graphs/flow_eventflatten.graphml deleted file mode 100644 index a0385cfe..00000000 --- a/doc/media/graphs/flow_eventflatten.graphml +++ /dev/null @@ -1,149 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - <E> - r - - - - - - - - - - - - - - - - - <E> - inner - - - - - - - - - - - - - - - - - <Events<E>> - - - - - - - - - outer - - - - - - - - - - - - - - - - - [e,...] - - - - - - - - - - - - [e,...] - - - - - - - - - - - - - inner - - - - - - - - - - - - - - - - - - - - - diff --git a/doc/media/graphs/flow_eventflatten.png b/doc/media/graphs/flow_eventflatten.png deleted file mode 100644 index d9911717c271b1ccdcf995ef337759581c3c8012..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5218 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 gQ~&K_+J!^4j(e - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - <E> - r - - - - - - - - - - - - - - - - - <E> - source - - - - - - - - - - - - - - - - - [e if func(e), ...] - - - - - - - - - - - - [e,...] - - - - - - - - - - - - - - - - - - - - - diff --git a/doc/media/graphs/flow_filter.png b/doc/media/graphs/flow_filter.png deleted file mode 100644 index fd3454b2e7af195d8f27f0f7976068a422dd1cb1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4369 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 diff --git a/doc/media/graphs/flow_filter2.graphml b/doc/media/graphs/flow_filter2.graphml deleted file mode 100644 index beec03af..00000000 --- a/doc/media/graphs/flow_filter2.graphml +++ /dev/null @@ -1,197 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - <E> - r - - - - - - - - - - - - - - - - - <TDepValue1> - dep1 - - - - - - - - - - - - - - - - - <TDepValueN> - - - - - - - - - depN - - - - - - - - - - - - - - - - - ... - - - - - - - - - - - - - - - - - <E> - source - - - - - - - - - - - - - - - - - [e1 if func(e1,v1,...,vN), ...] - - - - - - - - - - - - v1 - - - - - - - - - - - - - vN - - - - - - - - - - - - - [e1,...] - - - - - - - - - - - - - - - - - - - - - diff --git a/doc/media/graphs/flow_filter2.png b/doc/media/graphs/flow_filter2.png deleted file mode 100644 index ae73e1fa178a0016e6d2ae3d0314dd96f8daa67a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8051 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 diff --git a/doc/media/graphs/flow_flatten.graphml b/doc/media/graphs/flow_flatten.graphml deleted file mode 100644 index ace5b909..00000000 --- a/doc/media/graphs/flow_flatten.graphml +++ /dev/null @@ -1,149 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - <S> - r - - - - - - - - - - - - - - - - - <S> - inner - - - - - - - - - - - - - - - - - <Signal<S>> - - - - - - - - - outer - - - - - - - - - - - - - - - - - v = x - - - - - - - - - - - - x - - - - - - - - - - - - - inner - - - - - - - - - - - - - - - - - - - - - diff --git a/doc/media/graphs/flow_flatten.png b/doc/media/graphs/flow_flatten.png deleted file mode 100644 index 561430cc1887dfd24f0a8e8f86ebea7de6154c10..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4622 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 F{{`srXvhEn diff --git a/doc/media/graphs/flow_hold.graphml b/doc/media/graphs/flow_hold.graphml deleted file mode 100644 index 16f1c40e..00000000 --- a/doc/media/graphs/flow_hold.graphml +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - <S> - r - - - - - - - - - - - - - - - - - <E> - events - - - - - - - - - - - - - - - - - INIT: v = init -STEP: v = e - - - - - - - - - - - - [e,...] - - - - - - - - - - - - - - - - - - - - - diff --git a/doc/media/graphs/flow_hold.png b/doc/media/graphs/flow_hold.png deleted file mode 100644 index 544e59cd8ae0166c985006cb12101007748548fa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4216 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 diff --git a/doc/media/graphs/flow_iterate.graphml b/doc/media/graphs/flow_iterate.graphml deleted file mode 100644 index ac293f3a..00000000 --- a/doc/media/graphs/flow_iterate.graphml +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - <S> - r - - - - - - - - - - - - - - - - - <E> - events - - - - - - - - - - - - - - - - - INIT: v = init -STEP: v = func(e,v) - - - - - - - - - - - - [e,...] - - - - - - - - - - - - - - - - - - - - - diff --git a/doc/media/graphs/flow_iterate.png b/doc/media/graphs/flow_iterate.png deleted file mode 100644 index 5f2e08e9b166ebfdb60f894b254efed6a0511516..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4677 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 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - <S> - r - - - - - - - - - - - - - - - - - <TDepValue1> - dep1 - - - - - - - - - - - - - - - - - <TDepValueN> - - - - - - - - - depN - - - - - - - - - - - - - - - - - ... - - - - - - - - - - - - - - - - - <E> - events - - - - - - - - - - - - - - - - - INIT: v = init -STEP: v = func(e,v,v1,...,vN) - - - - - - - - - - - - v1 - - - - - - - - - - - - - vN - - - - - - - - - - - - - [e,...] - - - - - - - - - - - - - - - - - - - - - diff --git a/doc/media/graphs/flow_iterate2.png b/doc/media/graphs/flow_iterate2.png deleted file mode 100644 index 8ee567e09a1c4934fc01edb91018fbca5e9055d6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8052 zcmZ{J1ys~gx9=b#C4(ZR44{NcN(l_DfPjD~64D*gFf@`XLk`^~NT+lOgA7Ox-KoTo z1JVumKl&K#Q&7lqyBHkY3?8Got`ORn^OkhqEJJrP2}d|=HP^V_L=XBR`1Adr-Bwj&V$2?l&Iz_%9<1WLpQ zfp`f29}9+H5U2$L{P5ot|GnS`1r~8z{@21kp6*vy@+n?;N!Nbq!mNglKuEsJu9 z>n$(kpL#wOK7Jqi@{)edwaLG z>{2k1tY#hEWRfw#^D@Y?AF8x`e-ut(PE{zX z4amc{VU+8k3VN^4jT($+_y~C9UO#;FsHmt&oT2}#Ttx5XDd`{2CLhw9H*Zo>Q){TJ zD=RD4FWgdjWwrb=LM{ngI(whBlh{7>s^Z5Z6-+=v?84D@hQSM;)iU4FK8IjAzKxw#F z9Ot~YSnh^~C)tUO;m#u|;E+#~UMExa3TlBwFiLW>vqy8)<@7!1iVeEI{In7{kA^{V zj9ZJg@?2k4gG}o&b@PdN=_>o+`cl`)nksnqyH+FQ!8EV;4FAl1v#95yn8-9P_93t~ z?s~k+nQEf@;v_Tf5S+A$!pIMeeLuU}YMr$E?>~tOil61!D|8QcG zj&_Qj9fO=}$l)3o{@Qd#Evfi&q&-xdSfqHNr0iz461Fi+mP9&P8XN`5KRrF3UAh1E z15HfT!QrXBm>qB@W&t=kV_$c7gZWGxsTo*{PgHcesb7O$qIedoTi2Mm*g6oY!O8VR zv&^7h8S41lqecbPQ4Tt4$akhOYp($PB%uJi^^MO9s$E0N*~XFmaz7X5+(0>??r?-W~p{`?7R zj!3VIth5+yovkKOJw5nT!H4CgMGhHzHM;Wi^ABeiB)2{DNO6Xc8#b6F8*MK1;_=1#d{x(4`*ev;^?gS*MGA!5 z=EUz1y*THWR_#osjSN{dHf6ewasjMq6nRT=ZJP3(lr50kyBKuJ!h&&dJ3h5EL^wFZ z_fkt$=k@D9Q>(v5$edmKsBH8;Q97}rqjya|Sc06tx7uh=bly2@OuCQ78b zc|Yk|mm$LIXbbx2xY_f7oe!%}9egKUAchU($OrfNk@xj0^X~%5566EN+Cx!#8?B#7 zxf@2PCyBR(IxW=(2*p|DWxstK>;`*_VzE)@*D-!F$&fI6Xb_ z;pCBPML#Huko*bx#Q?iWPX0u@>hU|1hVt_Asi~<=w@&yBDe!O%YCnwd>k^EkzYS$9a zV}~E{dwc57{2P4eVV}xB@&W?b`tfnbGo*F1Y+QQ5NALG=i=h}aVWbjl2cyJ zOWe!Lm*oUoA+RX*~LqJx1AQ`{jtAaHK#BV?6#bhp3cBL za~60!oTs8wX1SW#(BSFp?Ck1#I8ko0`&6?}v9d^Am5sOXwvhc?Z2tnw#%xz-r-S?W zhU+VLXjMhnc#&*QFmXxM2Ay1TN_GEq&3jm0-bz;V8{^Rg-O3jnL_H0vBXMOC9#mbd z34Z~iCJ>aUq2V~nCUXm3Lg8u1X%ilCbuO%@r^l>R#`j`lWF+=ONpbNAlA4BwhLW)uV=ngg_Vrtd|L*I1$rq|m@)L4<+i!vk@7CgpkIto{S9yX5>E24wx~8_k;hm>^R^lLY$a z=_oDLmB?hc&s|!WpENpiZhnOan?Iulda?W~!N5mBMP>e>x^vFGd-s<1Iy-~Xs8D=x z1d++f?(*quRC;>4;n_kw_X0By+yKH$rk?wwlSqAXGLhK|6J+dqjE=JkFMb?HThL?z zb|{4g1_tu+@hN4LMDsOo%jQYd*i14>xSt=Ff485h8^na%PLxJ2jSdYlRaR6~C<$4M z=`5dfFJKKy_!yo=`Yq7Oy?jZn%fNf^!AP#J|a@gRLOYRMJYG<}$!YvNYxuP?4pQkdUYbY_5?ngkzTme6XDkb+c-uD7H7YvxLW7L#J;7*k zaeY>)0p#x8Bx}!y&t6jhLErW68hpd0-L;+~RCMI_g-32ll=kZ;Q4Oi@2`SE=Q7-gx zXFEF`jE(uB$L})!l&{i72`(YJ!M%709=MZ^+;Zs{1EvLHO2QHh&2HIR=fz7KkQD<~ z67f}gAgYE2H8x2)BJ4tjkX@;Y3bjbN1Y%XO}9YRA{KzCK})O3j4_|?o0cCb}~Lgvmyg7{zWauBf4Go z_1%>lgWUKQ7p=M|u&Hicm4@0P{Crj8l@lfvo#LJX$z}8B54-7N14=$UQm~SGgx?jIrgXAEda#!FMxxb} zq;3w<>W@!2G=rLJ@|vZ~qvqmUW9#>SLafS0k@+_w^NERl5EwkaJVGXPx6v4Uxb36> zcgttkB~h@jh*kW0$~FABndLK^i#W@>TzNC@Co0&vv||!E5_6Ke76|zF&u}`xd+xqM z1SVX(hkRV!TTWR28X-^s6irM1(EHcz=PYZ*ea>{23pBi7!jo!!@W#4; zFFig7*LfC`kx4CXre7#*L~xdr=W#3Q&OsxczHGBJ+p+8lQ7Bkm@+@ znx8%c^e^Z@1$H<|*bEJ3#&f-uyy}ets!fSq`5ih;A}T-{PWy!z1iRictdYn}tE_x; z;JP0)k`VI^4s6Ct2Fg$1dqhtfSkIJt}CqLHLh%`_7`aWZ>VUvX~=)Vx7Gm zy>l@BZ$U0ZtT3ellbDoby&?CN4Ako{#v^B`j~tsi?FxOk@b3)HlJ1U96;@Q}+Jm)hu-bc6yo4Zt;0R^neFY3A!ZCHYn)V|U#3KhmJ8sR?15O@Dep*{wfvP!4=E#C@#2Q{P|oyD^W{-xnM{n^Q@1DhHsnyOoEKj82E* zE+2+=TxcUM8yDr_;o)f4=4a>NsI07RtEu{a;Uq3n0Ku{& zp${KE{H|YC?B2c4jrUIh>d{flAJJT<78aTs8m=xb?GLJRyHJ1^2f`9$N!=iC819&+R!NpvlQ2a*PEuPmbT>R%MOt6GeYO$_$E1bVd>MQ-lDxU(OyZ zGm!rD_v+z4U)-|=$b#e7Ua9@R*n$9Enj_BK+~NYt#G|ogP31 zSz749(haEy%_1Wdu*3uPK0~9(FqZb?+^XX4Qg-+NCo43w#BLB0ieON0Zx@)t9jEQl zHVHBCDRA)>6;lEOL=Gil3+9M~C!_YhMNO7ffP%Kn?gm8w_OLNl&>(Wd@*1$q$D{2B z#8U^E`|uycGBM+w{L(gOUikM8u(w}sjUaC0{pPmSH+p57q#Nq$9D<6W2B0VFMU^Ud^Ixjv@~bi|9xirC6dX$iSn zJ$L1W;1V0!n;m-g%1($ya`3ONUzqhw-If3F1E3R3p zTduW2bVyq|UL<~tDmtFp<(J<{alfQyT3Y#4&ow_X9>U(8g?7^0KY^gH0ff_W!JAfA zRyKA^_}j1`_W*J0jh(i|pYGcCe6{_qXFN>(WVZk$1}-ixK7Bmy#!qYrB?33jBJDa| z5;%DcoZR18AJM>T7H~EtH4zpO;d_RyWo2dc!QgrbXs%<4K)U0|QUYorD7W5FL#uMY z+iM`0AtD>_7?|!j4*jxm9yxveImPL4zObIRM%52$>$)Bcn+#IZ<4iM1LRwl{b^4ZV zr*95(s(zN0RaJWbNAYaykalH6gyfhN3+`aQkBR9J#`Da|tNk~_^KIX>He4*AC?*qsJb&yNb8-6YxxUbmJrzt|l`+j81qsgCrQgva`!*-I|y+W4u(4&W4%Vy1m{dZV$bK7Mh=F@=BmL(l3Yc#5hsk_bnRZAPSrq&twxckD&tVY@) zCwK1L**zI8(%jWjQA$O@l}3iY#H6Pq{)3r0pDKH*-1A^vCdtIr)pczs=h3Uw*HiBv z+5&aHiv01P6xy*&T)GXr_4#cddSOm`6obm6}B7S;5;pn=Sj1G7Tdf z1mG4#D9G&Wth&1T4pO>w4`?EtpPvIUDJzSqAfT?a?~SHrEztg|wV!t~HU_sq6pX>4 zg5J%c3e~7riY<{y+AVsgG-f%3shQc@c(L(4VH*arjh_)dDfIO87n_y+EEi%rpP~1u zzJBw;%r|)n0iX3IWtN&gJe&r#4L~-=%T$1}vmW*c7rAlI!Uq>-rq-Os1zNxCr*L#; z53~GUuCH<^{W%Aawz2d=wqEkPfN9S4&dxSAHlScflMV#EiTFHnESSicyz+8Kz^wfn&Aq!gCO9u( zo}Ql1p8aU{KGR3~U>hX+1Ig&LwYAO7%@_7yjjq^e{N-Nh2ZWi`)lWG%dR&q$#T&xD z0VUSSiU}Z`s6>;VcrE};W%F-F4H%ip>BPi4J-t~3y{PWd%57|WW>aP#(C?5f@7v!% zrw9R!2jtbImypIgX$1Ek&`ASipPBif7cY_726p{$hK384?`DhC)7A~2wx@?WE&ch8 z>JtM4dC(~ul#tB4w94nSl;ac(1u{Q+G7fh3rKMomH0dW}RMga`T)#qgpsiNYcD&B; z`;|c6VHUrZA%_TDYfcq)D+O9sW6}5%Gc%CgAuUtFZj5%H0NiB(8^#S=>7z#?nSfMa zU&5GUfE*0&p3HH3!Qn5#2|Hdm@Vub*Io)3ak`CZjnA$9_4!~`W8m}S%6--3V>zI>G8j5Mh^+kfm*`fh8ywvE&F0p3457vl2|B~yWh0T2GxO2aFXZIH%Z7)Cfm-?>!(u2W zg}sII-Des19*Od>$7eO<}o|_y}NhIk4u1do~YZ_v2v`X@YAPM z8Te)vT#x1-kjJ}=e(jMbo8E3^1LT#+{5{5?+W?J519@3QHB?tb0?0$_N4l0!fc59t zSPw&dFZVLW%M2uWcy4Xh0*VD@5L*>`Lo%pera4AZQ@KD_P+V183wQa#q|?Ks^3nEn z6J0b5(1xw45!9}1RsNnfXr?{q4>e5x!6?E?f^)E;LmyyQ8VZ%!V(A#3?nMFu0z=1qSQvLu*U~*s9xl50g?1VGNoae0dmVL4&^zJS5s3{QNdSGkvQg+F6I%P zl0x?m6?v=P9DQ#wm=j4wckiBQ$o%YVBq94u_4Bc5PQk~rw-nBShtGP-5zuz#b3mu} zqN&kqX~+HC>Qf@~Xi_>v@@RvVA}He$8^S@sxh7UAA*~O@i%J>2l7LSG6B837Ba~z8 z;^N}bnX26gl=jYyp_s4re6u%TSs{DxTNPHXU0%*(fj%Z?(DyVy#sCOm7JuVLs0H+1 zYRl46Hl~B0p)Za5;=bB4rPa%B zg@F2?%EH9{Z?E|cUx$J6u7mQ3aZU>GT)>3D5bWokMgh7-ft!K8VsH637nLFcCS`PV zbTm)&A#iOjfXab2PbK3JJ8AyUHIR;Zul1#g_NR;YJi`a|Ml}cs30at%ySlm2y)Bj- zk770RK)y=B14@UNJpBA`H8m45GPZ@5UdhUS4*FsIAxNjzZh2{`v!Q|j%nUL_s2Mpq zRWvkAE$)bU?swXc{rY7HsGNjn&YCcFYfFn1(7gnFyQxV79*`3sl^dY~tE#GiDvD6& zOHq;H2$SdP#s)F|m-o%g+`{XmT;8zSP>xI zv!Md;#$q-nE6K>n_UbRw0|EkY?XX!Edm9@uw=D=E+5c}S{BMr@cWnHBPM-g-1>j-+ hviM)K=^4}&{*@)!Nb=lyH!ybwDagK(DSd7j@L%@ugysMM diff --git a/doc/media/graphs/flow_makesignal.graphml b/doc/media/graphs/flow_makesignal.graphml deleted file mode 100644 index 74177539..00000000 --- a/doc/media/graphs/flow_makesignal.graphml +++ /dev/null @@ -1,206 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - <S> - r - - - - - - - - - - - - - - - - - <TValue1> - arg1 - - - - - - - - - - - - - - - - - <TValue2> - - - - - - - - - arg2 - - - - - - - - - - - - - - - - - <TValueN> - - - - - - - - - argN - - - - - - - - - - - - - - - - - ... - - - - - - - - - - - - - - - - - v = func(v1,v2,...,vN) - - - - - - - - - - - - v1 - - - - - - - - - - - - - v2 - - - - - - - - - - - - - vN - - - - - - - - - - - - - - - - - - - - - diff --git a/doc/media/graphs/flow_makesignal.png b/doc/media/graphs/flow_makesignal.png deleted file mode 100644 index 09412e5f5ee09c9f4b8476078fbd40e246194567..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6945 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 Pf - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - <E> - r - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - [...] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/doc/media/graphs/flow_makesource.png b/doc/media/graphs/flow_makesource.png deleted file mode 100644 index 89423d5ed5837cdb8637de68f5c74e10e8231d48..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1521 zcmY*ZeLT~79RH%zQlnQVrm0mPZk0TQal>xPh7Mz7od}tSY@VWRn#Cb1C(}-Q={zKH zB-BWh$9gpiNu`=4u@2Q48l&@czv*?={qg<2-rv{v^ZI<=pQra3cQ;44+9ovs0NmNh zfee811_-lZ%Ftb9v*ZcDclFK=_Fk<1@d2|i&!eDqD!F<(^>j>jUR-qa*hzQm^5Hkz zv1o6YdO;j_OWb}&%96dDK zr_wc0;i59{iXww@uka&B?$#=G2q}B@_vE^i-CtUqj~Z;={8|TrfJHrh7gs_yivR)- z6MpARLJ*zal?T~kFYx)r=&PN=;o-|as&F%B;2Ij$5yEUeM;AmAoj%r-MurQyw!lgZDn9s6@o{J-oYUjXGT$5 zl)#x_J&R(7LqQYkazjQ+X%y2Wf1L=n&#&H0Y7e-0%8CW2u#d z(25gS9%@ZMhTw*U`GG^BagQIRTRI|Q5%C#<-uNt45vVgllGGZaVd_yfVWWqzAtFVS zs47sE6@~ta@tE6|$V2kl7s8foI@HwjW?5NTBoZlVX|FVb_1gtF9&=tNw!zn}gq-VQ zcuq3etgtc`mF4^778VXRv1g&WiS?0feH9d1P{!pj7K;@b>4pKKFg|^qy1Mk`jUX!Z z3P<2k>8+t_eO)fFp9{qmR(tIfD0L9;iePPXb5lW2nMVIF*i2apor|@QNtF^08N63&iEX_$q2c-{}amA+0xYXItH=0xEQ0G_^F2$ ztjKci1^?&aw#Sd%%e}6$aa9oMZOCObzw=#>P$x$7OxwtgO%Ss6?{e?IVcGa6_<(}RDa1}W>2Stj5YF8XV)P>&87$k>Q8)t=FCMr^y z4=LV^fWbysO zw?$soYAv@Z?@!xlNE&g7Q{w|4g0obTDjyLi7ea8<;<^zQx#Olx>$%Q0L}1xkE1?|> zoPR*9)V=SYc=dj9_bo2G8#q}b3vq>&J{NPtWqm|MQLHD3$X?m@Zx4qX_M$LRh+NRmDz-t_4X zsbS0ij-Q(hT%5z$?K-}^wCHz-ajFOI-{z|vN5FVfC>khS-UF(Z7Q}V%#knnZKFpLq zNrlpZJIt`Kv2pRO((eQ2LnY8u6s^ue{d71n0q(1kI6dZ3FPf6HyZ+EB?;##ENbMsY zG)p~xZ@EL5p=}}`7i%{s_o?D3RLRqeG^9)>Ti$^jk`L89DzN*|uZq_WE*^Q9vx~#w zFr}}KDoEQfrPD4ulZ?BG?nYWY`8E_N$E8;j3!h{>9 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - <S> - r - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - v = init - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/doc/media/graphs/flow_makevar.png b/doc/media/graphs/flow_makevar.png deleted file mode 100644 index 07349c52aa0f6d03ba7bbc569f8ed2236beedfd8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1675 zcmZ8idpwj`7(U1)&Cn8UrioH1m6G*!am{5Anp}#?r81Iy2<4K|D5a(v*Q5!nOu0ld zGqu>py~ebnwG!hRle?j*#%0Lt$5y-TALsnu^E=OZ-gDmPoad1D@3TV7tH}cZ&^Fc< zjsQq1A#tRfB+?fe%sBxd<7i{C$2q)>-?7K~W`ugBK*EZssd-t>b20gX23bLH@k9BO z#?@ChoV=%CF6&}wy*0FTP~*}sf8JZ9h+S)T5T*JySB_rCD004PamAF#T}ocZiGfk% zqSd;nGLz6&56_TSs#Y1)*H`vr=lEoc^~8ediOfbDB8b+v4VME6Xh4txTwn?xtAiG^^LK_4Q@+eh z*0#jP#!gR1G|3>Vy|+`JYw5U^9Bn}MEX`yxUlM{3LD@Mu^(&&`g3(bf(>5*W^Pqz= z0=6_dKO61~jdfQ9RwHQr%VE_uzZyjbm!>b4N}x2OP^e{$o)&#T;C<>J7{I8hCB1y# z(UH!TOrX3rAk7hXXFvx)3Y8MZEu~&5&Qv_{b|iSmr|~M=?gAc`y$&}u6UfX~Kbp)G z)OB9yc|0sDPHYvWj<+R=r+Z?3KxMYK<{gKfn&K&bp3r?|!AxI{t)~@qJlCmvGExb^ zW>A;+fc(e}Pm)f2cj46_+^$~7ESG$x=GtOq4tx3Si124c4I5}N@%mObcHum-VCNP+ z8^{zY=X|QNOTWnTTY)9o)NaNgdc-#6@}#*5Xzpp&{0Ih&)fmRSm^axKb49wvNoZs) zfuiEZ3J)R@-4GH2O_J##UmJ%_Mki3VM9J&Sih|M~hK_Yiw|E#PqPgIq4#wZ#UteE8 zBO{|Pjk2?yeTz&c#~)d*rM1Lzb7O_asFcZ?N-r-jS%sCkj~*dd_ucmo1PHl!<-~c) zn-n>mai-^FO!vEH_C50}ZSCzQbM*ZDO~EA-VD>Veq^%n5tSv+YD>2@_U8&D?=J%>o zQXAr7J3KzM_np_1oVoHKb^h{!!70VLv>k!HqUvfhH+3v_3x8DgCGHqXntmf0efKYh zL)Lr>+~(Vd4<8nZM7`%oByoAv%wFSXmJGVc7%2n$76(@n#KUQ)T-ziN_SdKRkrut3 zwAAJT0?m*?FDYqlZ4DO=H~07VJF<>A4a4`FhQ`LmCda$$WRM!d&o>&ll?Fd3EG+!s zc)%vc0lvW43mHEvi1;EB3V5|%v*(lK3FZ*A0i!Zww@~WSYG+xdRBzgSLXAN3n-(18 zN+R)Bf#@=Nih;Eor)mT7DUDU)GeaXkhumOU{mays?(4+(EK0ThKa!*yO zRlM24Eh|#HNohhu&^icT@*GpJfaLw+24bj>h~%@lMVhg@g;5n+5|#Y~+WxqEq`5~+ zDg-rVWFW4Xf)Lz5W~yRjY4R@)VtN{BRtBM?SKHY}w{4>za&Sb=a1(#42kT@& zKwM-|8_2x|6J0-cv8SfO=}{l2iSF*53<{mpG2Bra($x-fv*2ZJ<-}dp+aTz-<1XjU zooh(n#XRFRTI$~pnb=70f54S9H#g_=`C?2*W+=a{xwEru)LnphR!`3{C%OG)-#uCC p|Naa9_3N+J{nfqaM|Xo~m!lkSIVE+xq9UIRu(8}{QD}Db;@^*RA=Cf> diff --git a/doc/media/graphs/flow_merge.graphml b/doc/media/graphs/flow_merge.graphml deleted file mode 100644 index ea36b912..00000000 --- a/doc/media/graphs/flow_merge.graphml +++ /dev/null @@ -1,205 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - <E> - r - - - - - - - - - - - - - - - - - <TValue1> - arg1 - - - - - - - - - - - - - - - - - <TValue2> - - - - - - - - - arg2 - - - - - - - - - - - - - - - - - <TValueN> - - - - - - - - - argN - - - - - - - - - - - - - - - - - ... - - - - - - - - - - - - - - - - - [e1,...,e2,...,eN,...] - - - - - - - - - - - - [e1,...] - - - - - - - - - - - - - [e2,...] - - - - - - - - - - - - - [eN,...] - - - - - - - - - - - - - - - - - - - - - diff --git a/doc/media/graphs/flow_merge.png b/doc/media/graphs/flow_merge.png deleted file mode 100644 index 79f11631daab7ba7fa0d0ff72429ae9d4c2b64c5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7452 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 diff --git a/doc/media/graphs/flow_monitor.graphml b/doc/media/graphs/flow_monitor.graphml deleted file mode 100644 index a5e67669..00000000 --- a/doc/media/graphs/flow_monitor.graphml +++ /dev/null @@ -1,110 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - <S> - r - - - - - - - - - - - - - - - - - <S> - target - - - - - - - - - - - - - - - - - [t] - - - - - - - - - - - - t - - - - - - - - - - - - - - - - - - - - - diff --git a/doc/media/graphs/flow_monitor.png b/doc/media/graphs/flow_monitor.png deleted file mode 100644 index d4f3d67406f88c73faf81cbb5bd3159edc2580c5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3515 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 bk*an;nx6rp&=WLe&`&3=&0hX^`Ir9yY8=fF diff --git a/doc/media/graphs/flow_observe.graphml b/doc/media/graphs/flow_observe.graphml deleted file mode 100644 index 66187620..00000000 --- a/doc/media/graphs/flow_observe.graphml +++ /dev/null @@ -1,109 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - r - - - - - - - - - - - - - - - - - <E> - subject - - - - - - - - - - - - - - - - - func(e), ... - - - - - - - - - - - - [e,...] - - - - - - - - - - - - - - - - - - - - - diff --git a/doc/media/graphs/flow_observe.png b/doc/media/graphs/flow_observe.png deleted file mode 100644 index de427401c7a7fe8fa5f9808903758fcda8e5af6d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4412 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 W@4O{T$ber(07E^vZt+#yi2njeGJ+8R diff --git a/doc/media/graphs/flow_observe2.graphml b/doc/media/graphs/flow_observe2.graphml deleted file mode 100644 index 37013734..00000000 --- a/doc/media/graphs/flow_observe2.graphml +++ /dev/null @@ -1,109 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - r - - - - - - - - - - - - - - - - - <S> - subject - - - - - - - - - - - - - - - - - func(s) - - - - - - - - - - - - s - - - - - - - - - - - - - - - - - - - - - diff --git a/doc/media/graphs/flow_observe2.png b/doc/media/graphs/flow_observe2.png deleted file mode 100644 index 82f519c70caeff46206f998976096663cb7732cb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3987 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 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - r - - - - - - - - - - - - - - - - - <TDepValue1> - dep1 - - - - - - - - - - - - - - - - - <TDepValueN> - - - - - - - - - depN - - - - - - - - - - - - - - - - - ... - - - - - - - - - - - - - - - - - <E> - subject - - - - - - - - - - - - - - - - - func(e,d1,...,dN), ... - - - - - - - - - - - - d1 - - - - - - - - - - - - - dN - - - - - - - - - - - - - [e,...] - - - - - - - - - - - - - - - - - - - - - diff --git a/doc/media/graphs/flow_observe3.png b/doc/media/graphs/flow_observe3.png deleted file mode 100644 index ad86b97679fd95b23fa300064ad29bdb02f175fd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8143 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 LYv~e6;}8D@tAUo4 diff --git a/doc/media/graphs/flow_pulse.graphml b/doc/media/graphs/flow_pulse.graphml deleted file mode 100644 index c89f4ee3..00000000 --- a/doc/media/graphs/flow_pulse.graphml +++ /dev/null @@ -1,141 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - <S> - r - - - - - - - - - - - - - - - - - <S> - target - - - - - - - - - - - - - - - - - <E> - trigger - - - - - - - - - - - - - - - - - [t,t,...] - - - - - - - - - - - - t - - - - - - - - - - - - - [...] - - - - - - - - - - - - - - - - - - - - - diff --git a/doc/media/graphs/flow_pulse.png b/doc/media/graphs/flow_pulse.png deleted file mode 100644 index b669ce4e7a2f5ad3624f66d4fe19b1dd1626a1d6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5700 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 diff --git a/doc/media/graphs/flow_snapshot.graphml b/doc/media/graphs/flow_snapshot.graphml deleted file mode 100644 index daf1bc3a..00000000 --- a/doc/media/graphs/flow_snapshot.graphml +++ /dev/null @@ -1,142 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - <S> - r - - - - - - - - - - - - - - - - - <S> - target - - - - - - - - - - - - - - - - - <E> - trigger - - - - - - - - - - - - - - - - - INIT: v = t -STEP: v = t - - - - - - - - - - - - t - - - - - - - - - - - - - [...] - - - - - - - - - - - - - - - - - - - - - diff --git a/doc/media/graphs/flow_snapshot.png b/doc/media/graphs/flow_snapshot.png deleted file mode 100644 index db28dfdb457766633da5dede781b59c6a2f85146..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5731 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 Sx&nsB5G{2bwUX<$VgCh%RLar- diff --git a/doc/media/graphs/flow_transform.graphml b/doc/media/graphs/flow_transform.graphml deleted file mode 100644 index 957fe523..00000000 --- a/doc/media/graphs/flow_transform.graphml +++ /dev/null @@ -1,110 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - <T> - r - - - - - - - - - - - - - - - - - <E> - source - - - - - - - - - - - - - - - - - [func(e), ...] - - - - - - - - - - - - [e,...] - - - - - - - - - - - - - - - - - - - - - diff --git a/doc/media/graphs/flow_transform.png b/doc/media/graphs/flow_transform.png deleted file mode 100644 index 9e76db2e74adf639c67ce7743b1d320e363c63e4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4321 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 diff --git a/doc/media/graphs/flow_transform2.graphml b/doc/media/graphs/flow_transform2.graphml deleted file mode 100644 index 85baa006..00000000 --- a/doc/media/graphs/flow_transform2.graphml +++ /dev/null @@ -1,197 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - <T> - r - - - - - - - - - - - - - - - - - <TDepValue1> - dep1 - - - - - - - - - - - - - - - - - <TDepValueN> - - - - - - - - - depN - - - - - - - - - - - - - - - - - ... - - - - - - - - - - - - - - - - - <E> - source - - - - - - - - - - - - - - - - - [func(e,d1,...,dN), ...] - - - - - - - - - - - - d1 - - - - - - - - - - - - - dN - - - - - - - - - - - - - [e,...] - - - - - - - - - - - - - - - - - - - - - diff --git a/doc/media/graphs/flow_transform2.png b/doc/media/graphs/flow_transform2.png deleted file mode 100644 index 0af4bdd1301b2b4207186b8a6e565a3f9855dbeb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7915 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 diff --git a/doc/media/helloworld.graphml b/doc/media/helloworld.graphml deleted file mode 100644 index 00b98c9f..00000000 --- a/doc/media/helloworld.graphml +++ /dev/null @@ -1,222 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bothWords - - - - - - - - - - - - - - - - - secondWord - - - - - - - - - - - - - - - - - - - - - - - - - firstWord - - - - - - - - - - - - - - - - - v = "Hello" + " " + "World - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "World" - - - - - - - - - - - - - "Hello" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/doc/media/helloworld.png b/doc/media/helloworld.png deleted file mode 100644 index 3e23d09a257e0fde697f5804cdd63b1b4577b1f3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7126 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 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - a - - - - - - - - - - - - - - - - - - b - - - - - - - - - - - - - - - - - - c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - x - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/doc/media/reactives2.graphml b/doc/media/reactives2.graphml deleted file mode 100644 index dda20611..00000000 --- a/doc/media/reactives2.graphml +++ /dev/null @@ -1,358 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - a - - - - - - - - - - - - - - - - - b - - - - - - - - - - - - - - - - - c - - - - - - - - - - - - - - - - - x - - - - - - - - - - - - - - - - - 2 - - - - - - - - - - - - - - - - - 2 - - - - - - - - - - - - - - - - - 2 - - - - - - - - - - - - - - - - - 1 - - - - - - - - - - - - - - - - - 1 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/doc/media/signals1.graphml b/doc/media/signals1.graphml deleted file mode 100644 index 5f2c894a..00000000 --- a/doc/media/signals1.graphml +++ /dev/null @@ -1,178 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - a - - - - - - - - - - - - - - - - - - b - - - - - - - - - - - - - - - - - - c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - x - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/doc/media/signals1.png b/doc/media/signals1.png deleted file mode 100644 index 372383bf2d5bef80f80fdfc8fa243f177c7a485d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3869 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 Hrw9K4*hpy? diff --git a/doc/media/signals2.graphml b/doc/media/signals2.graphml deleted file mode 100644 index 03a90b8a..00000000 --- a/doc/media/signals2.graphml +++ /dev/null @@ -1,358 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - a - - - - - - - - - - - - - - - - - b - - - - - - - - - - - - - - - - - c - - - - - - - - - - - - - - - - - x - - - - - - - - - - - - - - - - - 2 - - - - - - - - - - - - - - - - - 2 - - - - - - - - - - - - - - - - - 2 - - - - - - - - - - - - - - - - - 1 - - - - - - - - - - - - - - - - - 1 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/doc/media/signals2.png b/doc/media/signals2.png deleted file mode 100644 index 019f747b18dbd5860253d67e48ae8221a661a0a4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9576 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 diff --git a/doc/media/toposort1.graphml b/doc/media/toposort1.graphml deleted file mode 100644 index 1cf13a90..00000000 --- a/doc/media/toposort1.graphml +++ /dev/null @@ -1,579 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - a - - - - - - - - - - - - - - - - - b - - - - - - - - - - - - - - - - - c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - x - - - - - - - - - - - - - - - - - a - - - - - - - - - - - - - - - - - b - - - - - - - - - - - - - - - - - c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - x - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - a - - - - - - - - - - - - - - - - - b - - - - - - - - - - - - - - - - - c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - x - - - - - - - - - - - - - - - - - b <<= K - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - level 0 - - - - - - - - - - - - - - - - - level 1 - - - - - - - - - - - - - - - - - level 2 - - - - - - - - - - - - - - - - - x=(a+b)*c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/doc/media/toposort1.png b/doc/media/toposort1.png deleted file mode 100644 index bf7270ee9f51d7e86cb20e82814425079b0b835c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 25492 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 r{3t?B_}32#*#eOt - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - task 1 - - - - - - - - - - - - - - - - - P= { - - - - - - - - - - - - - - - - - } - - - - - - - - - - - - - - - - - task 2 - - - - - - - - - - - - - - - - - task 3 - - - - - - - - - - - - - - - - - task 4 - - - - - - - - - - - - - - - - - - heavy - - - - - - - - - - - - - - - - - - light - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/doc/media/toposort2.png b/doc/media/toposort2.png deleted file mode 100644 index 87f36465eaf0d199bfe8364893890938fe5b203a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10369 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 ac4_4C)HTriFTm_%WGV{kcM9YlJ^No2rQ@ss diff --git a/doc/media/toposort3.graphml b/doc/media/toposort3.graphml deleted file mode 100644 index 69529a72..00000000 --- a/doc/media/toposort3.graphml +++ /dev/null @@ -1,156 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - op2 - - - - - - - - - - - - - - - - - op1 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - delayed by op2 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/doc/media/toposort3.png b/doc/media/toposort3.png deleted file mode 100644 index d60b848a68ad6010db2027f2ecb78e3f8c2f89bb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7912 zcmZvh2UJr{xAzf6=^#?1qx9aShN7T=fb=R&5Qs<#y(NHB1q7uAqzMWrRp~VdNJkKr zUP7n>hCpaZfaE(q?{mL(@49!^Iwx6^GiN3C#biP?M37(cRa(YX*EC zk&#`Xrz8iyE$#Q)lacY%-oJatB6JR25anezi6^xOJJ>aTaDFUNVPaWaHPR+$)>vV} zV#%7!_n7_CRg+s`gIZIr@mp=_sUPZenhbZ!UIz80TNn=_Zo-9zyhg*CfHFKj86rL!k^qq1F9R2n3?5t7~UBpDy0B zL&vEYt5s|x5xo56d7!F;2=mO7wfVqrV`F7zAD=&e?pf37eqVun|NQ*Cg?A}*l}?c# zuV`d$Zr&b(nMw)tepv5L_mc3@ynN>U+B~IOz3ufs#*x?zdNb7X<}+ckDUytitpi(2KJ5Ed z39?ib#exV64ZRL_HqXH5&`dRVb~=D%nG(NbPvaX~?dgd_!&%}%(_F@6ipqGO*VJ+3 zCR5)O&lsyW zL1+>TDv>kkJ>Nv-i}DTi@fpK_DI}WnuhOe--@Y`|EbZI-kmf1n70wNr_hzE|mL>_g zx$I_o2=!otwzf8b%)7p`%hX?JfVoJq@lzFBn>P@?1M~TUF6u?s1gc8D=w$=LHSote zX?k}T();av5?I)DDV8*C1&~M7w`t7wTJs!vaV!4y+$#RD%ITQ41s`@%3aE$P<+j>d zEi%U)owbD=^>thHqHRrOFJ2_#LSoujykQ8ZTeI z{Qh)tZF?d%15=@(piuf!i5L!Q`YOJD5EjU^+%FeKL5I zL5ll^5c%aF_Yos{;lW8jx5wnHEuAvYX7h){z zitT7r28PdoAe}Mvo`r>nmlsSD#MfBJ5x-_%E&puua@BY+q;v&$2g~j1ccz4=Z&8j) z09xfo-ABY!&Cc4|Ce9?`4?ak4j%Q%RT>A*Z=_=hc{`V1;jH68wPm0Dj>8ftfHhJ+6 z9#sy8piRqih3pGuUP=swNWRI$Fa z#W$GlBRn$^Q86mA`F~!_PEGYMZViPvyvfP=e$wF;9??Rg#~<7D_V!-hExIgj#5&Zh zw2ek9c#{mo`yeZ_O7uj4s`yZQWXm;PH$Nd=)Ucm#Zxw$#6n4bDsFJ-Q53CC~I;OP3_tF3{6Rw@w*|DTmNjpc zCQt-B>@r%!Gp9qG)G~zV)3V}L`P8^5Z{m+{@7-$ho-g~by|v}B`$3((Ur#y?27Pya zdLo@I@6q81MJw!^DHHQx)0IEVjYl|W$rfY9hR(QK3|s9}0W+Tq`uRXfG-t0TAAd>i z3r*@Zu*z#pxa9g91<#icW1PdoA9gTHf%FibhlYmkdf6#`ow`5=*23!GACr@AZyDZB zzjma?*G#D1Y`GPDZliu&3fDr2XBEcC3xMl#1VX5!`$q5G9%}YWcT)gdsTVQ8$zODV z>op8Mjp|J(Wl+oe_QuKi65LH!!EEi6w3VW?^m_90wZvG-$;h=d-8Z1)WSHGXZeUQ5 z?X6tv@zTTNVuCxls;a6I1-�`WvEv?^orzKK9h}2IA`LZqBr*pIZ%T3)O?U5<)GO zSnWg0MtWY2QBh6FuOWbkF)WZneVTGPUfFL!Yd%o4@PI(zETW83Cx?fO3sxvQ$%}c0 zLTn9__il%gS+V8j~pygkbW7g8;~)M=SpDP6uY{4E*_d%99;9HcI(gma&z~QSM&BT?OzDgWsKFE%A?FFu!@7v$dG-Q8VrN-9F;1PcLv7X+d)za=BX_t;9@ zDVfDcvBrE~hL&Bw0y_V^!{`|cvns7hWaQ(yTv)ru)2B~Qb{8k5WbKC@&eb7u-(+*j z)I0p()wU7UoRtl?YCM>0^i+p{u?`Psy;$Slhh~M&(x84%yn9v`Djl1cNOirqySqCb z#Xm|rEMdRZO8aS6O7zSo>tXl!^nBQCom-z!*w3;Dppe~;%|a;R91V%WK#`oSH#_2y z(X6{WJM$f32j!aQ9&ljff`#c5Pk!AA27`rb=$_SxVYRQVPDm{NV!ES&TaFp_YF>`M zfrmM=W9z}=B?a8Bz4G1dWQ0>BiKy3S=0j+lcHDWgi9$J7>Z*p0D^=AZCiv$>m=b?! zW-@TCwthT)8+!irnsI}d`*I%gtjs3_F6EFk!_o5Um+&pQs(7EgJ+4p9?Y|5Vlf;hj zpUbUV1CHqg(dEFVxoG8zf}naj%}bY|UqR^EdhqEnnowAf-Bb^Tt%{cEYVOfTEYjE@ z%Oseow~Sz);)038)`$|$X$WkUlb=W#l2(}T`Ex-hiqqZFy-y3}JA;df2&O z=d8yaxtc9$w`LuMA8}f0h9F-Q=?gH0D^&!cJHBSL%` z3n(5{%M=mY=0$Zi1v@L8M$x#1XY-l~^A1~q4;d3)UGK10j!gTnx|1bnEuW78Xu7X? z)FOcc(#maR&&3i-y0B^o+5DGO`jUcc3Ls?OJvz`fX(>i76@LL4-**LqER;pi_p{N` zKBl1QL8XN|LtH2gMFDxS2gs=@)|Y|Qb9nh8{7Y8@4px&k&(;2vriOqNnC?5%#IkQ& zT?K%t8XC#Cx9EXl-lI^ctMUyHqz1bTI21J9(~O|-t#=vj%N%kgmrv$FOBCL(chQH} z@QTm1vLf6(tU6@&gzq1DDWS01ir#a#TnbIZ59V8+BHR{b&J+R$gEWfZ1IeAMITK^U zq0$a*zve#+I(kgkIHViMHWgHEfOuY27R3r@e)i>C%epg~jg>?%Oin7eR4`&Wmc}Oc zQ%uarX)>lK$JYHGf!=|{TG)};k^4#uO1KhImFl}q)kl{ zdpy@bQP>7Md|dy-<3}Lt?q;<_j;?~WQUf?o=<p^?A-j>argdgaSz6hw7oojD?;Li`R0gg_=mm$A}#F@)E!A@AIAk&cCLe z;f(^Y2bS%u=KUC?P&bp=ZbUCe9M6K2@!8NQ=C|zhPg9Vt^Cn^=p)2bkC0zfl`&HzRF+!3# z{rMlTra3EH(+0fjOfYr1whpA68o~{WI-JmzmzN)QHy8qJ*0^;}Dt!B6xe3$pQYr1W z$3Ih>V*{6C&^(i&h8n#vr*1I>xbLxb2~FbuD{04$7o24?XurXk;Nu(&dcOG`nTzj$ zUju(CWVWtv-@C7V&SHog6#N>(RybCq`6~UDCb4BzIXX9P#B&vdi^L8I8)UqMHkW-7q{|NT)@7pMG}YLR3m!#sO^f`^zDIvq;(&J7ou{F2ay)cCj6F z`MIK27iG6W4BV;~bpj?+3_X*Gz^(K)YD-CutFdRz3uRB`|D?|~Ly8QDYsCpX{*S^p z3qrCx+N8=qmnc!!SO3 z;v_p&bGF6ru_YcdIY8fqpU~wE+N<`T(Inx={VpME72R*+aPN4}^;k|PYa=OYHwr?Q zx|5%t9=my1wht6pC`axA9!5_8E~YE+P`_ezAeB4d5Bv9}rQIdX;r$pFpX6HdROPB# zRpNjq@#>##!Oe}0$nza1gU@w#X_unT9<8r-P1vOAt!-D>1xCMtL1|X3&M-I2-BTd?c{{}n*tx7Zuko)h3e33X(yhBqsqhI1EYdfU$L{- zZL__=^6*b)5tH%F0g|xs(a}NjsIpQu`P`SN5&o&EF#rl0jvi0isP@jc>M$t(uYja#*>OG7~Yu{3Loog2xe^gjV*^Dp87a3uX;gDjqJmTvX6eTeNsItLY- zy!J}06X}j`cLhNfS|%_LE&@@5tAUpncwFZh*%O>A;T8pHVIR;W!hF_g+6=cC3g4A9 z%fsY>N6d zgYbZWpqkMPH_8I<4~C$jU?(<=gQ=!NYP=KrE6P|K3sce@FpRWXVFGeT*p z)_3SgmdhlosAyHKGQN30X%kd#F8DM)K0bOvdn*idkznW3TKX^m;W;gJscKK`;?$VN z*jtsLZ41AhN-{21?&mZT-wzKP3O#x}xt_0TXlT%D-@FzZaTMk??SiIlr%6TxY>ok9 zh8p2;^2z?+5EdDEik@%s4p6%i{c8*%eI5SIy%+UqS9V$`RETeBX@9|M^AT1uUL{Na z=;UN%C7gwN-C1wBq`@dY7VX80Ecr*FiwTZRqm0wqvpf`kKCS#?agjSk2UTTkWYqM~ z2Y5^gSt{;~66N|_?oJfP%PvY}9~r?%~% zsF9mIedZO4kR`4`g-ah?tKLW)J~@H)8PHYvBWm1Mx$lz`eO6>;HCS|^BL zx_0__c=LdMvwckcis&#OqL@gG9C#zwAzy~ z12Ger_7!?A6PPA;kiUb+;ybRepunNt{Trb5#k2*{PyT>ur|G%+`o3n1sVjsuN;%5q zz8qNX?Cj*`=I+~BiTkT(UhWbsF#5?~F0ssMq$ifeas9eT>#v5>wz7Ye%$7(Ax0}fS z$e1<3t&TOM2f1S*ig|I}Qan5&r%GJv;fIG?Kl@IV4F3w2z5EF$X0)oKD#LrjrVmy* z|EFN-FgauWmR8puNoNwY%D})7K;o{Tg7p%%FJA0+5ny^QS$p6a(8_g|ktJ@uU87P+ z))8wFgR?r7+ji%S)Vp}xwdP7W9D+be0!1?VI?n2F8 zwChiwzk*~Y7}k5Av53?6bknz8yugTNWv_3x)Htj+M1V=w^(ncJq@Ts|`9Yi65ti;P zg(z;}0ZDMLZ`~c_zeXu7X$eC5w!6J&{!@B`{fRBH0toK6m@9%2?bp>Ii|Z0154SEWnG?$N?c%7&c~SN;(tzt~w-SeH|6hOfoHadpBM zzIkKT&l%OpZMTwj=oYihE^UOcOT&b!)qIx?OZ18Dkh95$0lM1{A-QW;;umIw1_2%{IoW4+oPofDfY zC|sl{lCY(7AgSHyo!c0BhV!#T?e6+uy(N&_vQT8i31E>o%-R5u+s6Q8G4llB*2sMj zW1#yY@maSW!YOQ>WkFuts%oY+U^5Sb*m}EmhCc`a+EtA7&@kJ)EKf{K1nOQ`qSN9Fr zT21?|nPuB*D#&EUFS{8T31X&3!F?9njv!H|c^&QHM^8J%Rh|JM2rsF`<{dt}klSwK zS#e>y*8XdV{a~Z#^l%3Avu!ezSdCq?QPeMT%3SYi_}Muo%1O;%uhne$JupdzMioB_ zS}qJ1_H>2|;Z!jD> zkX%O3Y5UDSjicolhKg>xiZFwk#h>l;V^}D#-=yhQ^lKN!3bpT%R35Sph`tbh28uXX#TEB0HxGMBm zqJ!g-L8@=b1hHAt!0&V|3RF`Xlb*h(QqxeV^h`EhmnPgdh`T|Q;Ec8y5-toaNjGn? zu4O`8<;w=fCxh-o#yo56slWYc_ZcSxZwuCOy)j4gV<~smMZR&DP;$bN`L(sLVZJCT zIBzWwSqu0T$6R!i!*r1%zb2FE>9-aAUF#kGod@FJ%gy$)s>+wZ@2aAr^X^7jkCSN- ze!o-p->Giyna0XMM$SSc(Jdhu$8}6a&S=_O+*k-AW*XS$N=wnjX4XdPD+bu=sY$Xp zU)AJ0mz0KiMwBxDSxIblv}va9+r%i|@ZZICK{gVI4qw~w{0gwg9_v_%mgAP71@!I8 zFBW>jUMEQ|*YIKY2@co7dk$~W3zzzn3fldCq30;Tb(m}*SsGz8dJ=K6Xs!6ca_ABz z7rbfCNYg<9B_paCQh92y>f&M{s! z#^TkguF`&z%She1V5}X4_%OjNMlu;yD(nNO+$q}SlVcR&XHinExZxXrZ*DuQmi!X0 zqa?f)E1OeX7v)7RH`dA+?Y|})QMXdJT=kAVwf^s(xXp$63)8yi-1~+H_zhflKj6CG zaVRbL#!Lq7DWd!Lk-RiglH8<}ss3yBD(ipaugRcKF&K(5q{rJe+3FL%hYzoK;s6|u z_c$jU`POzFH`Zo-yOQU0Wj)jGOY@xgQptaE8&?eNNoypq(O!uxT8|I-uaWx&OUL!l4mNk5W4J7sdi0!S`mgD~mLxhO=MhSEt<`PsVN4Jj-8pekGe zLWG$*UD6ata+pW%S97sMu)jY(4*vh_889zbT2z+>aWg;S-paah5-fCyhZ)Fy!I-in zKYA0$?;$*|Y8h@3(vEs|cn$OZ<;rUbVLlZTFzr27SMg9&FnDuj#-?#Yt!SM8(PRNM z>jOInhYN$?Bo`vfs6f@yuvI_sONlTOl??$%1gO7Dm{ukqh=9S=Sd)h?IXgx006bLV zrN~L25cH~5v0MJa{?W_LvcYDjXlJ8RGk`|wUO2~Tg~o@075xa4u)D*UEoO_~QQs!2cr!>@`8U5Xag}^Koua4#;4W O-M?paw?^wx^#23rgiR&@ From 244fa1cb99671f876c8aa3fff9c5ed206c427175 Mon Sep 17 00:00:00 2001 From: schlangster Date: Tue, 29 Jul 2014 23:44:22 +0200 Subject: [PATCH 11/86] Updated readme. --- README.md | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index a580cce6..a10f27b3 100644 --- a/README.md +++ b/README.md @@ -93,24 +93,30 @@ SignalT area = MakeSignal( return w * h; }); ``` -``` -// Signal values can be accessed imperativly +Signal values can be accessed imperatively: +```C++ cout << "area: " << area.Value() << endl; // => area: 2 -// VarSignals can be manipulated imperatively -width.Set(10); // Width changed, so area is re-calculated automatically +width.Set(10); 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` in this case for a more concise syntax: ```C++ // Lift as reactive expression - equivalent to previous example SignalT area = width * height; ``` -### Event streams and Observers +### 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: @@ -129,7 +135,7 @@ EventSourceT rightClicked = MakeEventSource(); EventsT merged = leftClicked | rightClicked; // React to events -auto obs = Observe(merged, [] (Token) { +Observe(merged, [] (Token) { cout << "clicked!" << endl; }); ``` From 1659bf4ce62c8f6f7050f04c771995e1676d51a5 Mon Sep 17 00:00:00 2001 From: schlangster Date: Wed, 30 Jul 2014 14:03:43 +0200 Subject: [PATCH 12/86] 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 13/86] 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 14/86] 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 15/86] 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 16/86] 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 17/86] 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 18/86] 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 19/86] 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 20/86] 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 21/86] 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 22/86] 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 23/86] 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 24/86] 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 25/86] 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 26/86] 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 27/86] 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 28/86] 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 29/86] 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 30/86] 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 31/86] 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 32/86] 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 33/86] 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 34/86] 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 35/86] 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 36/86] 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 37/86] 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 38/86] 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 39/86] 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 40/86] 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 41/86] 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 42/86] 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 43/86] 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 44/86] 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 45/86] 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 46/86] 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 47/86] 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 48/86] 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 49/86] 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 50/86] 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 51/86] 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 52/86] 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 53/86] 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 54/86] 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 55/86] 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 56/86] 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 57/86] 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 58/86] 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 59/86] 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 60/86] 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 61/86] 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 62/86] 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 63/86] 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 64/86] 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 65/86] 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 66/86] 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 67/86] 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 68/86] 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 69/86] 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 70/86] 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 71/86] 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 72/86] 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 73/86] 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 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 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 74/86] 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 75/86] 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 76/86] 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 77/86] 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 78/86] 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 79/86] 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