From 978e59aa92f8c7efd6c0b285f164e8acde6729b3 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Mon, 18 Mar 2019 23:38:12 -0700 Subject: [PATCH] Fabric: ShadowNodeFamily, maintaining a pointer to a parent family Summary: One of the core feature of ShadowNodeFamily is having a pointer to a parent family. This diff implements it. I don't think there is a hard retain cycle there, but for more lean memory usage we use weak_ptr here. Reviewed By: JoshuaGross Differential Revision: D14416948 fbshipit-source-id: 05fd2c4833146f007228363b1d958776b4a2a9cf --- .../fabric/core/shadownode/ShadowNode.cpp | 14 ++++++++++++++ .../core/shadownode/ShadowNodeFamily.cpp | 10 ++++++++++ .../fabric/core/shadownode/ShadowNodeFamily.h | 18 ++++++++++++++++++ 3 files changed, 42 insertions(+) diff --git a/ReactCommon/fabric/core/shadownode/ShadowNode.cpp b/ReactCommon/fabric/core/shadownode/ShadowNode.cpp index d32e65602..15a16d33c 100644 --- a/ReactCommon/fabric/core/shadownode/ShadowNode.cpp +++ b/ReactCommon/fabric/core/shadownode/ShadowNode.cpp @@ -46,6 +46,10 @@ ShadowNode::ShadowNode( revision_(1) { assert(props_); assert(children_); + + for (const auto &child : *children_) { + child->family_->setParent(family_); + } } ShadowNode::ShadowNode( @@ -71,6 +75,12 @@ ShadowNode::ShadowNode( assert(props_); assert(children_); + + if (fragment.children) { + for (const auto &child : *children_) { + child->family_->setParent(family_); + } + } } UnsharedShadowNode ShadowNode::clone(const ShadowNodeFragment &fragment) const { @@ -139,6 +149,8 @@ void ShadowNode::appendChild(const SharedShadowNode &child) { auto nonConstChildren = std::const_pointer_cast(children_); nonConstChildren->push_back(child); + + child->family_->setParent(family_); } void ShadowNode::replaceChild( @@ -161,6 +173,8 @@ void ShadowNode::replaceChild( std::replace( nonConstChildren->begin(), nonConstChildren->end(), oldChild, newChild); + + newChild->family_->setParent(family_); } void ShadowNode::setLocalData(const SharedLocalData &localData) { diff --git a/ReactCommon/fabric/core/shadownode/ShadowNodeFamily.cpp b/ReactCommon/fabric/core/shadownode/ShadowNodeFamily.cpp index 5cab78038..ab623b337 100644 --- a/ReactCommon/fabric/core/shadownode/ShadowNodeFamily.cpp +++ b/ReactCommon/fabric/core/shadownode/ShadowNodeFamily.cpp @@ -20,5 +20,15 @@ ShadowNodeFamily::ShadowNodeFamily( eventEmitter_(eventEmitter), componentDescriptor_(componentDescriptor) {} +void ShadowNodeFamily::setParent(ShadowNodeFamily::Shared const &parent) const { + assert(parent_.lock() == nullptr || parent_.lock() == parent); + if (hasParent_) { + return; + } + + parent_ = parent; + hasParent_ = true; +} + } // namespace react } // namespace facebook diff --git a/ReactCommon/fabric/core/shadownode/ShadowNodeFamily.h b/ReactCommon/fabric/core/shadownode/ShadowNodeFamily.h index 41f8370f7..5e5a55b4a 100644 --- a/ReactCommon/fabric/core/shadownode/ShadowNodeFamily.h +++ b/ReactCommon/fabric/core/shadownode/ShadowNodeFamily.h @@ -32,6 +32,13 @@ class ShadowNodeFamily { SharedEventEmitter const &eventEmitter, ComponentDescriptor const &componentDescriptor); + /* + * Sets the parent. + * This is not techically thread-safe, but practically it mutates the object + * only once (and the model enforces that this first call is not concurent). + */ + void setParent(ShadowNodeFamily::Shared const &parent) const; + private: friend ShadowNode; @@ -55,6 +62,17 @@ class ShadowNodeFamily { * type. */ ComponentDescriptor const &componentDescriptor_; + + /* + * Points to a family of all parent nodes of all nodes of the family. + */ + mutable ShadowNodeFamily::Weak parent_{}; + + /* + * Represents a case where `parent_` is `nullptr`. + * For optimization purposes only. + */ + mutable bool hasParent_{false}; }; } // namespace react