Skip to content

Commit c861dae

Browse files
committed
Added ReactiveLoop.
1 parent 5a66e1a commit c861dae

7 files changed

Lines changed: 360 additions & 4 deletions

File tree

include/react/ReactiveDomain.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ template
4242
auto MakeSignal(F&& func, const RSignal<D,TArgs>& ... args)
4343
-> RSignal<D, typename std::result_of<F(TArgs...)>::type>;
4444

45+
template <typename D>
46+
class RReactiveLoop;
47+
4548
/************************************/ REACT_END /*************************************/
4649

4750
/*********************************/ REACT_IMPL_BEGIN /*********************************/
@@ -94,6 +97,8 @@ class DomainBase
9497

9598
using Observer = RObserver<D>;
9699

100+
using ReactiveLoop = RReactiveLoop<D>;
101+
97102
////////////////////////////////////////////////////////////////////////////////////////
98103
/// ObserverRegistry
99104
////////////////////////////////////////////////////////////////////////////////////////

include/react/ReactiveObject.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ class ReactiveObject
4242

4343
using Observer = RObserver<D>;
4444

45+
using ReactiveLoop = RReactiveLoop<D>;
46+
4547
////////////////////////////////////////////////////////////////////////////////////////
4648
/// MakeVar
4749
////////////////////////////////////////////////////////////////////////////////////////

include/react/Reactor.h

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
2+
// Copyright Sebastian Jeckel 2014.
3+
// Distributed under the Boost Software License, Version 1.0.
4+
// (See accompanying file LICENSE_1_0.txt or copy at
5+
// http://www.boost.org/LICENSE_1_0.txt)
6+
7+
#pragma once
8+
9+
#ifndef REACT_DISABLE_REACTORS
10+
11+
#include "react/Defs.h"
12+
13+
#include <functional>
14+
#include <memory>
15+
16+
#include "ReactiveBase.h"
17+
#include "ReactiveDomain.h"
18+
19+
#include "react/common/Util.h"
20+
21+
#include "react/EventStream.h"
22+
#include "react/graph/ReactorNodes.h"
23+
24+
/***********************************/ REACT_BEGIN /************************************/
25+
26+
template <typename D>
27+
class RReactiveLoop
28+
{
29+
public:
30+
class Context;
31+
32+
using NodeT = REACT_IMPL::ReactorNode<D,Context>;
33+
34+
class Context
35+
{
36+
public:
37+
Context(NodeT& node) :
38+
node_{ node }
39+
{
40+
}
41+
42+
template <typename E>
43+
E& Take(const REvents<D,E>& evn)
44+
{
45+
return node_.Take<E>(evn.GetPtr());
46+
}
47+
48+
template <typename E, typename F>
49+
void RepeatUntil(const REvents<D,E>& evn, F func)
50+
{
51+
node_.RepeatUntil<E>(evn.GetPtr(), func);
52+
}
53+
54+
private:
55+
NodeT& node_;
56+
};
57+
58+
template <typename F>
59+
RReactiveLoop(F&& func) :
60+
nodePtr_{ new REACT_IMPL::ReactorNode<D, Context>(std::forward<F>(func), false) }
61+
{
62+
nodePtr_->StartLoop();
63+
}
64+
65+
private:
66+
std::unique_ptr<NodeT> nodePtr_;
67+
};
68+
69+
/************************************/ REACT_END /*************************************/
70+
71+
#endif //REACT_DISABLE_REACTORS

include/react/graph/ReactorNodes.h

Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
2+
// Copyright Sebastian Jeckel 2014.
3+
// Distributed under the Boost Software License, Version 1.0.
4+
// (See accompanying file LICENSE_1_0.txt or copy at
5+
// http://www.boost.org/LICENSE_1_0.txt)
6+
7+
#pragma once
8+
9+
#ifndef REACT_DISABLE_REACTORS
10+
11+
#include "react/Defs.h"
12+
13+
#include <cstdint>
14+
#include <functional>
15+
#include <memory>
16+
#include <unordered_map>
17+
#include <utility>
18+
19+
#include <boost/coroutine/all.hpp>
20+
21+
#include "GraphBase.h"
22+
#include "EventStreamNodes.h"
23+
24+
/*********************************/ REACT_IMPL_BEGIN /*********************************/
25+
26+
////////////////////////////////////////////////////////////////////////////////////////
27+
/// ReactorNode
28+
////////////////////////////////////////////////////////////////////////////////////////
29+
template
30+
<
31+
typename D,
32+
typename TContext
33+
>
34+
class ReactorNode :
35+
public ReactiveNode<D,void,void>
36+
{
37+
public:
38+
using NodeBasePtrT = NodeBase<D>::PtrT;
39+
40+
using CoroutineT = boost::coroutines::coroutine<const NodeBasePtrT*>;
41+
using LoopT = typename CoroutineT::pull_type;
42+
using OutT = typename CoroutineT::push_type;
43+
44+
using TurnT = typename D::Engine::TurnInterface;
45+
46+
template <typename F>
47+
ReactorNode(F&& func, bool registered) :
48+
ReactiveNode<D,void,void>(true),
49+
func_{ std::forward<F>(func) }
50+
{
51+
}
52+
53+
void StartLoop()
54+
{
55+
// Could already have started it in ctor,
56+
// but lets make sure node is fully constructed before calls to
57+
// context in coroutine can happen.
58+
mainLoop_ = LoopT
59+
(
60+
[&] (OutT& out)
61+
{
62+
curOutPtr_ = &out;
63+
64+
TContext ctx{ *this };
65+
66+
while (true)
67+
{
68+
func_(ctx);
69+
}
70+
}
71+
);
72+
73+
// First blocking event is not initiated by Tick() but after loop creation.
74+
const auto* p = mainLoop_.get();
75+
76+
REACT_ASSERT(p != nullptr, "StartLoop: first depPtr was null");
77+
78+
Engine::OnNodeAttach(*this, **p);
79+
++depCount_;
80+
}
81+
82+
virtual const char* GetNodeType() const override { return "ReactorNode"; }
83+
84+
virtual bool IsDynamicNode() const override { return true; }
85+
86+
virtual ETickResult Tick(void* turnPtr) override
87+
{
88+
turnPtr_ = static_cast<TurnT*>(turnPtr);
89+
REACT_SCOPE_EXIT{ turnPtr_ = nullptr; };
90+
91+
mainLoop_();
92+
93+
if (mainLoop_.get() != nullptr)
94+
{
95+
const auto& depPtr = *mainLoop_.get();
96+
Engine::OnDynamicNodeAttach(*this, *depPtr, *turnPtr_);
97+
++depCount_;
98+
99+
return ETickResult::invalidated;
100+
}
101+
102+
offsets_.clear();
103+
104+
return ETickResult::none;
105+
}
106+
107+
virtual int DependencyCount() const override
108+
{
109+
return depCount_;
110+
}
111+
112+
template <typename E>
113+
E& Take(const EventStreamNodePtr<D,E>& events)
114+
{
115+
// First attach to target event node
116+
(*curOutPtr_)(&std::static_pointer_cast<NodeBase<D>>(events));
117+
118+
while (! checkEvent<E>(events))
119+
(*curOutPtr_)(nullptr);
120+
121+
REACT_ASSERT(turnPtr_ != nullptr, "Take: turnPtr_ was null");
122+
123+
Engine::OnDynamicNodeDetach(*this, *events, *turnPtr_);
124+
--depCount_;
125+
126+
return events->Events()[offsets_[reinterpret_cast<uintptr_t>(&events)]++];
127+
}
128+
129+
template <typename E, typename F>
130+
void RepeatUntil(const EventStreamNodePtr<D,E>& events, F func)
131+
{
132+
// First attach to target event node
133+
if (turnPtr_ != nullptr)
134+
{
135+
(*curOutPtr_)(&std::static_pointer_cast<NodeBase<D>>(events));
136+
}
137+
else
138+
{
139+
// Non-dynamic attach in case first loop until is encountered before the loop was
140+
// suspended for the first time.
141+
Engine::OnNodeAttach(*this, *events);
142+
++depCount_;
143+
}
144+
145+
// Detach when this function is exited
146+
REACT_SCOPE_EXIT
147+
{
148+
if (turnPtr_ != nullptr)
149+
Engine::OnDynamicNodeDetach(*this, *events, *turnPtr_);
150+
else
151+
Engine::OnNodeDetach(*this, *events);
152+
--depCount_;
153+
};
154+
155+
// Don't enter loop if event already present
156+
if (checkEvent<E>(events))
157+
return;
158+
159+
auto* parentOutPtr = curOutPtr_;
160+
REACT_SCOPE_EXIT{ curOutPtr_ = parentOutPtr; };
161+
162+
// Create and start loop
163+
LoopT nestedLoop_
164+
{
165+
[&] (OutT& out)
166+
{
167+
curOutPtr_ = &out;
168+
while (true)
169+
func();
170+
}
171+
};
172+
173+
// First suspend from initial loop run
174+
(*parentOutPtr)(nestedLoop_.get());
175+
176+
// Further iterations
177+
while (! checkEvent<E>(events))
178+
{
179+
// Advance loop, forward blocking event to parent, and suspend
180+
nestedLoop_();
181+
(*parentOutPtr)(nestedLoop_.get());
182+
}
183+
}
184+
185+
private:
186+
template <typename E>
187+
bool checkEvent(const EventStreamNodePtr<D,E>& events)
188+
{
189+
if (turnPtr_ == nullptr)
190+
{
191+
return false;
192+
}
193+
194+
events->SetCurrentTurn(*turnPtr_);
195+
return offsets_[reinterpret_cast<uintptr_t>(&events)] < events->Events().size();
196+
}
197+
198+
std::function<void(TContext&)> func_;
199+
200+
LoopT mainLoop_;
201+
TurnT* turnPtr_;
202+
203+
OutT* curOutPtr_ = nullptr;
204+
205+
int depCount_ = 0;
206+
207+
std::unordered_map<std::uintptr_t, std::size_t> offsets_;
208+
};
209+
210+
/**********************************/ REACT_IMPL_END /**********************************/
211+
212+
#endif //REACT_DISABLE_REACTORS

project/msvc/CppReact.vcxproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@
7777
</Link>
7878
</ItemDefinitionGroup>
7979
<ItemGroup>
80+
<ClInclude Include="..\..\include\react\graph\ReactorNodes.h" />
8081
<ClInclude Include="..\..\include\react\Options.h" />
8182
<ClInclude Include="..\..\include\react\common\Concurrency.h" />
8283
<ClInclude Include="..\..\include\react\common\Containers.h" />
@@ -111,6 +112,7 @@
111112
<ClInclude Include="..\..\include\react\ReactiveDomain.h" />
112113
<ClInclude Include="..\..\include\react\ReactiveBase.h" />
113114
<ClInclude Include="..\..\include\react\ReactiveObject.h" />
115+
<ClInclude Include="..\..\include\react\Reactor.h" />
114116
<ClInclude Include="..\..\include\react\Signal.h" />
115117
<ClInclude Include="..\..\include\react\Traits.h" />
116118
</ItemGroup>

project/msvc/CppReact.vcxproj.filters

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,12 @@
147147
<ClInclude Include="..\..\include\react\Traits.h">
148148
<Filter>Header Files</Filter>
149149
</ClInclude>
150+
<ClInclude Include="..\..\include\react\Reactor.h">
151+
<Filter>Header Files</Filter>
152+
</ClInclude>
153+
<ClInclude Include="..\..\include\react\graph\ReactorNodes.h">
154+
<Filter>Header Files\graph</Filter>
155+
</ClInclude>
150156
</ItemGroup>
151157
<ItemGroup>
152158
<ClCompile Include="..\..\src\react\common\Util.cpp">

0 commit comments

Comments
 (0)