Skip to content

Commit f96fd6b

Browse files
committed
Added FoldByRef and IterateByRef to algorithms. Iteration func modifies current state by reference without copy and comparison. Downside: Comparison to previous value is no longer possible, so always assuming a change.
1 parent 4f4cb6f commit f96fd6b

3 files changed

Lines changed: 205 additions & 1 deletion

File tree

include/react/Algorithm.h

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,27 @@ auto Fold(V&& init, const Events<D,E>& events, FIn&& func)
5454
std::forward<V>(init), events.NodePtr(), std::forward<FIn>(func)));
5555
}
5656

57+
///////////////////////////////////////////////////////////////////////////////////////////////////
58+
/// FoldByRef - Pass current value as reference
59+
///////////////////////////////////////////////////////////////////////////////////////////////////
60+
template
61+
<
62+
typename D,
63+
typename V,
64+
typename E,
65+
typename FIn,
66+
typename S = std::decay<V>::type
67+
>
68+
auto FoldByRef(V&& init, const Events<D,E>& events, FIn&& func)
69+
-> Signal<D,S>
70+
{
71+
using F = std::decay<FIn>::type;
72+
73+
return Signal<D,S>(
74+
std::make_shared<REACT_IMPL::FoldByRefNode<D,S,E,F>>(
75+
std::forward<V>(init), events.NodePtr(), std::forward<FIn>(func)));
76+
}
77+
5778
///////////////////////////////////////////////////////////////////////////////////////////////////
5879
/// Iterate
5980
///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -75,6 +96,27 @@ auto Iterate(V&& init, const Events<D,E>& events, FIn&& func)
7596
std::forward<V>(init), events.NodePtr(), std::forward<FIn>(func)));
7697
}
7798

99+
///////////////////////////////////////////////////////////////////////////////////////////////////
100+
/// IterateByRef
101+
///////////////////////////////////////////////////////////////////////////////////////////////////
102+
template
103+
<
104+
typename D,
105+
typename V,
106+
typename E,
107+
typename FIn,
108+
typename S = std::decay<V>::type
109+
>
110+
auto IterateByRef(V&& init, const Events<D,E>& events, FIn&& func)
111+
-> Signal<D,S>
112+
{
113+
using F = std::decay<FIn>::type;
114+
115+
return Signal<D,S>(
116+
std::make_shared<REACT_IMPL::IterateByRefNode<D,S,E,F>>(
117+
std::forward<V>(init), events.NodePtr(), std::forward<FIn>(func)));
118+
}
119+
78120
///////////////////////////////////////////////////////////////////////////////////////////////////
79121
/// Hold
80122
///////////////////////////////////////////////////////////////////////////////////////////////////

include/react/detail/graph/AlgorithmNodes.h

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,62 @@ class FoldNode : public FoldBaseNode<D,S,E>
108108
}
109109
};
110110

111+
///////////////////////////////////////////////////////////////////////////////////////////////////
112+
/// FoldByRefNode
113+
///////////////////////////////////////////////////////////////////////////////////////////////////
114+
template
115+
<
116+
typename D,
117+
typename S,
118+
typename E,
119+
typename TFunc
120+
>
121+
class FoldByRefNode : public SignalNode<D,S>
122+
{
123+
public:
124+
template <typename T, typename F>
125+
FoldByRefNode(T&& init, const SharedPtrT<EventStreamNode<D,E>>& events, F&& func) :
126+
SignalNode(std::forward<T>(init)),
127+
func_{ std::forward<F>(func) },
128+
events_{ events }
129+
{
130+
Engine::OnNodeCreate(*this);
131+
Engine::OnNodeAttach(*this, *events);
132+
}
133+
134+
~FoldByRefNode()
135+
{
136+
Engine::OnNodeDetach(*this, *events_);
137+
Engine::OnNodeDestroy(*this);
138+
}
139+
140+
virtual void Tick(void* turnPtr) override
141+
{
142+
using TurnT = typename D::Engine::TurnT;
143+
TurnT& turn = *reinterpret_cast<TurnT*>(turnPtr);
144+
145+
REACT_LOG(D::Log().template Append<NodeEvaluateBeginEvent>(
146+
GetObjectId(*this), turn.Id()));
147+
148+
for (const auto& e : events_->Events())
149+
func_(value_,e);
150+
151+
REACT_LOG(D::Log().template Append<NodeEvaluateEndEvent>(
152+
GetObjectId(*this), turn.Id()));
153+
154+
// Always assume change
155+
Engine::OnNodePulse(*this, turn);
156+
}
157+
158+
virtual const char* GetNodeType() const override { return "FoldByRefNode"; }
159+
virtual int DependencyCount() const override { return 1; }
160+
161+
protected:
162+
TFunc func_;
163+
164+
SharedPtrT<EventStreamNode<D,E>> events_;
165+
};
166+
111167
///////////////////////////////////////////////////////////////////////////////////////////////////
112168
/// IterateNode
113169
///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -150,6 +206,62 @@ class IterateNode : public FoldBaseNode<D,S,E>
150206
}
151207
};
152208

209+
///////////////////////////////////////////////////////////////////////////////////////////////////
210+
/// IterateByRefNode
211+
///////////////////////////////////////////////////////////////////////////////////////////////////
212+
template
213+
<
214+
typename D,
215+
typename S,
216+
typename E,
217+
typename TFunc
218+
>
219+
class IterateByRefNode : public SignalNode<D,S>
220+
{
221+
public:
222+
template <typename T, typename F>
223+
IterateByRefNode(T&& init, const SharedPtrT<EventStreamNode<D,E>>& events, F&& func) :
224+
SignalNode(std::forward<T>(init)),
225+
func_{ std::forward<F>(func) },
226+
events_{ events }
227+
{
228+
Engine::OnNodeCreate(*this);
229+
Engine::OnNodeAttach(*this, *events);
230+
}
231+
232+
~IterateByRefNode()
233+
{
234+
Engine::OnNodeDetach(*this, *events_);
235+
Engine::OnNodeDestroy(*this);
236+
}
237+
238+
virtual void Tick(void* turnPtr) override
239+
{
240+
using TurnT = typename D::Engine::TurnT;
241+
TurnT& turn = *reinterpret_cast<TurnT*>(turnPtr);
242+
243+
REACT_LOG(D::Log().template Append<NodeEvaluateBeginEvent>(
244+
GetObjectId(*this), turn.Id()));
245+
246+
for (const auto& e : events_->Events())
247+
func_(value_);
248+
249+
REACT_LOG(D::Log().template Append<NodeEvaluateEndEvent>(
250+
GetObjectId(*this), turn.Id()));
251+
252+
// Always assume change
253+
Engine::OnNodePulse(*this, turn);
254+
}
255+
256+
virtual const char* GetNodeType() const override { return "IterateByRefNode"; }
257+
virtual int DependencyCount() const override { return 1; }
258+
259+
protected:
260+
TFunc func_;
261+
262+
SharedPtrT<EventStreamNode<D,E>> events_;
263+
};
264+
153265
///////////////////////////////////////////////////////////////////////////////////////////////////
154266
/// HoldNode
155267
///////////////////////////////////////////////////////////////////////////////////////////////////

src/test/OperationsTest.h

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,54 @@ TYPED_TEST_P(OperationsTest, Snapshot1)
213213
ASSERT_EQ(snap(), 20);
214214
}
215215

216+
///////////////////////////////////////////////////////////////////////////////////////////////////
217+
/// FoldByRef1 test
218+
///////////////////////////////////////////////////////////////////////////////////////////////////
219+
TYPED_TEST_P(OperationsTest, FoldByRef1)
220+
{
221+
auto src = MyDomain::MakeEventSource<int>();
222+
auto f = FoldByRef(
223+
std::vector<int>(),
224+
src,
225+
[] (std::vector<int>& v, int d) {
226+
v.push_back(d);
227+
});
228+
229+
// Push
230+
for (auto i=1; i<=100; i++)
231+
src << i;
232+
233+
ASSERT_EQ(f().size(), 100);
234+
235+
// Check
236+
for (auto i=1; i<=100; i++)
237+
ASSERT_EQ(f()[i-1], i);
238+
}
239+
240+
///////////////////////////////////////////////////////////////////////////////////////////////////
241+
/// IterateByRef1 test
242+
///////////////////////////////////////////////////////////////////////////////////////////////////
243+
TYPED_TEST_P(OperationsTest, IterateByRef1)
244+
{
245+
auto src = MyDomain::MakeEventSource();
246+
auto x = IterateByRef(
247+
std::vector<int>(),
248+
src,
249+
[] (std::vector<int>& v) {
250+
v.push_back(123);
251+
});
252+
253+
// Push
254+
for (auto i=0; i<100; i++)
255+
src.Emit();
256+
257+
ASSERT_EQ(x().size(), 100);
258+
259+
// Check
260+
for (auto i=0; i<100; i++)
261+
ASSERT_EQ(x()[i], 123);
262+
}
263+
216264
///////////////////////////////////////////////////////////////////////////////////////////////////
217265
REGISTER_TYPED_TEST_CASE_P
218266
(
@@ -223,7 +271,9 @@ REGISTER_TYPED_TEST_CASE_P
223271
Monitor1,
224272
Hold1,
225273
Pulse1,
226-
Snapshot1
274+
Snapshot1,
275+
FoldByRef1,
276+
IterateByRef1
227277
);
228278

229279
} // ~namespace

0 commit comments

Comments
 (0)