Skip to content

Commit 942582d

Browse files
committed
Implemented FlattenObjectNode.
Removed ObjectState. FlattenObject does the same but is more flexible. Cleanup.
1 parent a2c3041 commit 942582d

6 files changed

Lines changed: 82 additions & 237 deletions

File tree

‎include/react/algorithm.h‎

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,47 @@ template <template <typename ...> class TMap, typename K, typename V, typename .
222222
auto FlattenMap(const State<TMap<K, State<V>, TParams ...>>& map) -> State<TMap<K, V>>
223223
{ return FlattenMap(map.GetGroup(), map); }
224224

225+
///////////////////////////////////////////////////////////////////////////////////////////////////
226+
/// Flattened
227+
///////////////////////////////////////////////////////////////////////////////////////////////////
228+
template <typename C>
229+
class Flattened : public C
230+
{
231+
public:
232+
using C::C;
233+
234+
Flattened(const C& base) :
235+
C( base )
236+
{ }
237+
238+
Flattened(const C& base, REACT_IMPL::FlattenedInitTag) :
239+
C( base ),
240+
initMode_( true )
241+
{ }
242+
243+
Flattened(const C& base, REACT_IMPL::FlattenedInitTag, std::vector<REACT_IMPL::NodeId>&& emptyMemberIds) :
244+
C( base ),
245+
initMode_( true ),
246+
memberIds_( std::move(emptyMemberIds) ) // This will be empty, but has pre-allocated storage. It's a tweak.
247+
{ }
248+
249+
template <typename T>
250+
Ref<T> Flatten(State<T>& signal)
251+
{
252+
if (initMode_)
253+
memberIds_.push_back(GetInternals(signal).GetNodeId());
254+
255+
return GetInternals(signal).Value();
256+
}
257+
258+
private:
259+
bool initMode_ = false;
260+
std::vector<REACT_IMPL::NodeId> memberIds_;
261+
262+
template <typename T, typename TFlat>
263+
friend class impl::FlattenObjectNode;
264+
};
265+
225266
///////////////////////////////////////////////////////////////////////////////////////////////////
226267
/// FlattenObject
227268
///////////////////////////////////////////////////////////////////////////////////////////////////

‎include/react/api.h‎

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ static constexpr InPlaceTag in_place = InPlaceTag::value;
5353
// Group
5454
class Group;
5555

56+
// Ref
57+
template <typename T>
58+
using Ref = std::reference_wrapper<const T>;
59+
5660
// State
5761
template <typename S>
5862
class State;
@@ -66,12 +70,8 @@ class StateSlot;
6670
template <typename S>
6771
class StateLink;
6872

69-
// Object state
7073
template <typename S>
71-
class ObjectContext;
72-
73-
template <typename T>
74-
class ObjectState;
74+
using StateRef = State<Ref<S>>;
7575

7676
// Event
7777
enum class Token;
@@ -94,10 +94,6 @@ using EventValueSink = std::back_insert_iterator<std::vector<E>>;
9494
// Observer
9595
class Observer;
9696

97-
// Ref
98-
template <typename T>
99-
using Ref = std::reference_wrapper<const T>;
100-
10197
template <typename T>
10298
bool HasChanged(const T& a, const T& b)
10399
{ return !(a == b); }

‎include/react/detail/algorithm_nodes.h‎

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -571,6 +571,8 @@ class FlattenStateMapNode : public StateNode<TMap<K, V>>
571571
InputMapType inner_;
572572
};
573573

574+
struct FlattenedInitTag { };
575+
574576
///////////////////////////////////////////////////////////////////////////////////////////////////
575577
/// FlattenObjectNode
576578
///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -579,32 +581,51 @@ class FlattenObjectNode : public StateNode<TFlat>
579581
{
580582
public:
581583
FlattenObjectNode(const Group& group, const State<T>& obj) :
582-
StateNode::StateNode( in_place, group, GetInternals(obj).Value(), 1 )
584+
StateNode::StateNode( in_place, group, GetInternals(obj).Value(), FlattenedInitTag{ } ),
585+
obj_( obj )
583586
{
584587
this->RegisterMe();
588+
this->AttachToMe(GetInternals(obj).GetNodeId());
585589

586-
for (NodeId id : Value().memberIds_)
587-
{
588-
this->AttachToMe(id);
589-
}
590+
for (NodeId nodeId : Value().memberIds_)
591+
this->AttachToMe(nodeId);
590592

591-
Value().mode = 0;
593+
this->Value().initMode_ = false;
592594
}
593595

594596
~FlattenObjectNode()
595597
{
596-
for (NodeId id : Value().memberIds_)
597-
this->DetachFromMe(id);
598+
for (NodeId nodeId : Value().memberIds_)
599+
this->DetachFromMe(nodeId);
598600

601+
this->DetachFromMe(GetInternals(obj_).GetNodeId());
599602
this->UnregisterMe();
600603
}
601604

602605
virtual UpdateResult Update(TurnId turnId) noexcept override
603606
{
607+
const T& newValue = GetInternals(obj_).Value();
608+
609+
if (HasChanged(newValue, static_cast<const T&>(this->Value())))
610+
{
611+
for (NodeId nodeId : this->Value().memberIds_)
612+
this->DetachFromMe(nodeId);
613+
614+
// Steal array from old value for new value so we don't have to re-allocate.
615+
// The old value will freed after the assignment.
616+
this->Value().memberIds_.clear();
617+
this->Value() = TFlat { newValue, FlattenedInitTag{ }, std::move(this->Value().memberIds_) };
618+
619+
for (NodeId nodeId : this->Value().memberIds_)
620+
this->AttachToMe(nodeId);
621+
622+
return UpdateResult::shifted;
623+
}
624+
604625
return UpdateResult::changed;
605626
}
606-
607627
private:
628+
State<T> obj_;
608629
};
609630

610631
/****************************************/ REACT_IMPL_END /***************************************/

‎include/react/detail/state_nodes.h‎

Lines changed: 3 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ class StateVarNode : public StateNode<S>
8787
{
8888
isInputAdded_ = false;
8989

90-
if (! (this->Value() == newValue_))
90+
if (HasChanged(this->Value(), newValue_))
9191
{
9292
this->Value() = std::move(newValue_);
9393
return UpdateResult::changed;
@@ -310,14 +310,12 @@ class StateLinkNode : public StateNode<S>
310310
if (auto p = parent.lock())
311311
{
312312
auto* rawPtr = p->GetGraphPtr().get();
313-
output[rawPtr].push_back(
314-
[storedParent = std::move(p), storedValue = GetInternals(p->dep_).Value()] () mutable -> void
313+
output[rawPtr].push_back([storedParent = std::move(p), storedValue = GetInternals(p->dep_).Value()] () mutable -> void
315314
{
316315
NodeId nodeId = storedParent->GetNodeId();
317316
auto& graphPtr = storedParent->GetGraphPtr();
318317

319-
graphPtr->PushInput(nodeId,
320-
[&storedParent, &storedValue]
318+
graphPtr->PushInput(nodeId, [&storedParent, &storedValue]
321319
{
322320
storedParent->SetValue(std::move(storedValue));
323321
});
@@ -335,69 +333,6 @@ class StateLinkNode : public StateNode<S>
335333
VirtualOutputNode linkOutput_;
336334
};
337335

338-
///////////////////////////////////////////////////////////////////////////////////////////////////
339-
/// ObjectStateNode
340-
///////////////////////////////////////////////////////////////////////////////////////////////////
341-
template <typename S>
342-
class ObjectStateNode : public StateNode<ObjectContext<S>>
343-
{
344-
public:
345-
ObjectStateNode(const Group& group, S&& obj, const std::initializer_list<NodeId>& memberIds) :
346-
ObjectStateNode::StateNode( group, &object_ ),
347-
object_( std::move(obj) )
348-
{
349-
this->RegisterMe();
350-
351-
if (memberIds.size() == 0)
352-
{
353-
apply([this] (const auto& ... members)
354-
{
355-
REACT_EXPAND_PACK(memberIds_.push_back(GetInternals(members).GetNodeId()));
356-
REACT_EXPAND_PACK(this->AttachToMe(GetInternals(members).GetNodeId()));
357-
}, object_.GetReactiveMembers());
358-
}
359-
else
360-
{
361-
memberIds_.reserve(memberIds.size());
362-
363-
for (NodeId id : memberIds)
364-
{
365-
memberIds_.push_back(id);
366-
this->AttachToMe(id);
367-
}
368-
}
369-
}
370-
371-
template <typename ... Us>
372-
ObjectStateNode(InPlaceTag, const Group& group, Us&& ... args) :
373-
ObjectStateNode::StateNode( group, &object_ ),
374-
object_( group, std::forward<Us>(args) ... )
375-
{
376-
this->RegisterMe();
377-
378-
apply([this] (const auto& ... members)
379-
{ REACT_EXPAND_PACK(memberIds_.push_back(GetInternals(members).GetNodeId())); }, object_.GetReactiveMembers());
380-
}
381-
382-
~ObjectStateNode()
383-
{
384-
// TODO: This must happen inside of the node
385-
for (NodeId id : memberIds_)
386-
this->DetachFromMe(id);
387-
388-
this->UnregisterMe();
389-
}
390-
391-
virtual UpdateResult Update(TurnId turnId) noexcept override
392-
{
393-
return UpdateResult::changed;
394-
}
395-
396-
private:
397-
S object_;
398-
std::vector<NodeId> memberIds_;
399-
};
400-
401336
///////////////////////////////////////////////////////////////////////////////////////////////////
402337
/// StateInternals
403338
///////////////////////////////////////////////////////////////////////////////////////////////////

‎include/react/state.h‎

Lines changed: 3 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,9 @@ class StateVar : public State<S>
130130
friend bool operator!=(const StateVar<S>& a, StateVar<S>& b)
131131
{ return !(a == b); }
132132

133+
S* operator->()
134+
{ return &this->Value(); }
135+
133136
protected:
134137
StateVar(std::shared_ptr<REACT_IMPL::StateNode<S>>&& nodePtr) :
135138
StateVar::State( std::move(nodePtr) )
@@ -291,103 +294,6 @@ auto CreateRef(const State<S>& state) -> State<Ref<S>>
291294
return CreateWrappedNode<State<Ref<S>>, StateRefNode<S>>(state.GetGroup(), state);
292295
}
293296

294-
///////////////////////////////////////////////////////////////////////////////////////////////////
295-
/// ObjectContext
296-
///////////////////////////////////////////////////////////////////////////////////////////////////
297-
template <typename S>
298-
class ObjectContext
299-
{
300-
public:
301-
ObjectContext() = default;
302-
303-
ObjectContext(const ObjectContext&) = default;
304-
ObjectContext& operator=(const ObjectContext&) = default;
305-
306-
ObjectContext(ObjectContext&&) = default;
307-
ObjectContext& operator=(ObjectContext&&) = default;
308-
309-
S& GetObject()
310-
{ return *objectPtr_; }
311-
312-
const S& GetObject() const
313-
{ return *objectPtr_; }
314-
315-
template <typename U>
316-
const U& Get(const State<U>& member) const
317-
{ return GetInternals(member).Value(); }
318-
319-
template <typename U>
320-
const EventValueList<U>& Get(const Event<U>& member) const
321-
{ return GetInternals(member).Events(); }
322-
323-
private:
324-
template <typename ... Us>
325-
explicit ObjectContext(S* objectPtr) :
326-
objectPtr_( objectPtr )
327-
{ }
328-
329-
S* objectPtr_;
330-
331-
template <typename U>
332-
friend class impl::StateNode;
333-
};
334-
335-
///////////////////////////////////////////////////////////////////////////////////////////////////
336-
/// ObjectState
337-
///////////////////////////////////////////////////////////////////////////////////////////////////
338-
template <typename S>
339-
class ObjectState : public State<ObjectContext<S>>
340-
{
341-
public:
342-
// Construct with group
343-
template <typename ... Us>
344-
static ObjectState Create(const Group& group, S&& obj, const Us& ... members)
345-
{
346-
using REACT_IMPL::NodeId;
347-
348-
std::initializer_list<NodeId> memberIds = { GetInternals(members).GetNodeId() ... };
349-
350-
return CreateObjectStateNode(group, std::move(obj), memberIds);
351-
}
352-
353-
template <typename ... Us>
354-
static ObjectState Create(InPlaceTag, const Group& group, Us&& ... args)
355-
{ return CreateObjectStateNode(in_place, group, std::forward<Us>(args) ...); }
356-
357-
ObjectState() = default;
358-
359-
ObjectState(const ObjectState&) = default;
360-
ObjectState& operator=(const ObjectState&) = default;
361-
362-
ObjectState(ObjectState&&) = default;
363-
ObjectState& operator=(ObjectState&&) = default;
364-
365-
S* operator->()
366-
{ return &this->Value().GetObject(); }
367-
368-
protected:
369-
ObjectState(std::shared_ptr<REACT_IMPL::StateNode<ObjectContext<S>>>&& nodePtr) :
370-
ObjectState::State( std::move(nodePtr) )
371-
{ }
372-
373-
private:
374-
static auto CreateObjectStateNode(const Group& group, S&& obj, const std::initializer_list<REACT_IMPL::NodeId>& memberIds) -> decltype(auto)
375-
{
376-
using REACT_IMPL::ObjectStateNode;
377-
378-
return std::make_shared<ObjectStateNode<S>>(group, std::move(obj), memberIds);
379-
}
380-
381-
template <typename ... Us>
382-
static auto CreateObjectStateNode(InPlaceTag, const Group& group, Us&& ... args) -> decltype(auto)
383-
{
384-
using REACT_IMPL::ObjectStateNode;
385-
using REACT_IMPL::SameGroupOrLink;
386-
387-
return std::make_shared<ObjectStateNode<S>>(in_place, group, std::forward<Us>(args) ...);
388-
}
389-
};
390-
391297
/******************************************/ REACT_END /******************************************/
392298

393299
#endif // REACT_STATE_H_INCLUDED

0 commit comments

Comments
 (0)