diff --git a/ReactCommon/fabric/core/shadownode/ShadowNode.cpp b/ReactCommon/fabric/core/shadownode/ShadowNode.cpp index 15a16d33c..02c4302ce 100644 --- a/ReactCommon/fabric/core/shadownode/ShadowNode.cpp +++ b/ReactCommon/fabric/core/shadownode/ShadowNode.cpp @@ -7,6 +7,7 @@ #include "ShadowNode.h" +#include #include #include @@ -17,6 +18,8 @@ namespace facebook { namespace react { +using AncestorList = ShadowNode::AncestorList; + SharedShadowNodeSharedList ShadowNode::emptySharedShadowNodeSharedList() { static const auto emptySharedShadowNodeSharedList = std::make_shared(); @@ -197,6 +200,48 @@ void ShadowNode::setMounted(bool mounted) const { } } +AncestorList ShadowNode::getAncestors( + ShadowNode const &ancestorShadowNode) const { + auto ancestors = AncestorList{}; + auto families = better::small_vector{}; + auto ancestorFamily = ancestorShadowNode.family_.get(); + auto descendantFamily = family_.get(); + + auto family = descendantFamily; + while (family && family != ancestorFamily) { + families.push_back(family); + family = family->parent_.lock().get(); + } + + if (family != ancestorFamily) { + ancestors.clear(); + return ancestors; + } + + auto parentNode = &ancestorShadowNode; + for (auto it = families.rbegin(); it != families.rend(); it++) { + auto childFamily = *it; + auto found = bool{false}; + auto childIndex = int{0}; + for (const auto &childNode : *parentNode->children_) { + if (childNode->family_.get() == childFamily) { + ancestors.push_back({*parentNode, childIndex}); + parentNode = childNode.get(); + found = true; + break; + } + childIndex++; + } + + if (!found) { + ancestors.clear(); + return ancestors; + } + } + + return ancestors; +} + bool ShadowNode::constructAncestorPath( const ShadowNode &ancestorShadowNode, std::vector> &ancestors) const { diff --git a/ReactCommon/fabric/core/shadownode/ShadowNode.h b/ReactCommon/fabric/core/shadownode/ShadowNode.h index 8e184322c..0a97a628a 100644 --- a/ReactCommon/fabric/core/shadownode/ShadowNode.h +++ b/ReactCommon/fabric/core/shadownode/ShadowNode.h @@ -45,6 +45,11 @@ class ShadowNode : public virtual Sealable, public: using Shared = std::shared_ptr; using Weak = std::weak_ptr; + using AncestorList = better::small_vector< + std::pair< + std::reference_wrapper /* parentNode */, + int /* childIndex */>, + 64>; static SharedShadowNodeSharedList emptySharedShadowNodeSharedList(); @@ -138,6 +143,7 @@ class ShadowNode : public virtual Sealable, void setMounted(bool mounted) const; /* + * Deprecated. Use `getAncestors` instead. * Forms a list of all ancestors of the node relative to the given ancestor. * The list starts from the parent node and ends with the given ancestor node. * Returns `true` if successful, `false` otherwise. @@ -149,9 +155,19 @@ class ShadowNode : public virtual Sealable, * `childIndex` and `nodeId` tracking. */ bool constructAncestorPath( - const ShadowNode &rootShadowNode, + const ShadowNode &ancestorShadowNode, std::vector> &ancestors) const; + /* + * Returns a list of all ancestors of the node relative to the given ancestor. + * The list starts from the given ancestor node and ends with the parent node + * of `this` node. The elements of the list have a reference to some parent + * node and an index of the child of the parent node. + * Can be called from any thread. + * The theoretical complexity of the algorithm is `O(ln(n))`. Use it wisely. + */ + AncestorList getAncestors(ShadowNode const &ancestorShadowNode) const; + #pragma mark - DebugStringConvertible #if RN_DEBUG_STRING_CONVERTIBLE