mirror of
https://github.com/status-im/react-native.git
synced 2025-02-23 14:48:25 +00:00
Fabric: ShadowNode::backtrackAncestors(...)
Summary: We have to have a way to backtrack a pointer to a parent node and this is generalized version of that. This is the first naive implementations of the algorithm. We will invest in optimizing this later. Reviewed By: mdvacca Differential Revision: D12920856 fbshipit-source-id: 9facb4e16a0b5608feb6747df3804952025ef093
This commit is contained in:
parent
1f32b5d1da
commit
3ecf4eaccb
@ -146,6 +146,25 @@ void ShadowNode::cloneChildrenIfShared() {
|
|||||||
children_ = std::make_shared<SharedShadowNodeList>(*children_);
|
children_ = std::make_shared<SharedShadowNodeList>(*children_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ShadowNode::constructAncestorPath(
|
||||||
|
const ShadowNode &ancestorShadowNode,
|
||||||
|
std::vector<std::reference_wrapper<const ShadowNode>> &ancestors) const {
|
||||||
|
// Note: We have a decent idea of how to make it reasonable performant.
|
||||||
|
// This is not implemented yet though. See T36620537 for more details.
|
||||||
|
if (this == &ancestorShadowNode) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto &childShadowNode : *ancestorShadowNode.children_) {
|
||||||
|
if (constructAncestorPath(*childShadowNode, ancestors)) {
|
||||||
|
ancestors.push_back(std::ref(ancestorShadowNode));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
#pragma mark - DebugStringConvertible
|
#pragma mark - DebugStringConvertible
|
||||||
|
|
||||||
#if RN_DEBUG_STRING_CONVERTIBLE
|
#if RN_DEBUG_STRING_CONVERTIBLE
|
||||||
|
@ -101,6 +101,21 @@ class ShadowNode : public virtual Sealable,
|
|||||||
*/
|
*/
|
||||||
void setLocalData(const SharedLocalData &localData);
|
void setLocalData(const SharedLocalData &localData);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
* Thread-safe if the subtree is immutable.
|
||||||
|
* The theoretical complexity of this algorithm is `O(n)`. Use it wisely.
|
||||||
|
* The particular implementation can use some tricks to mitigate the
|
||||||
|
* complexity problem up to `0(ln(n))` but this is not guaranteed.
|
||||||
|
* Particular consumers should use appropriate cache techniques based on
|
||||||
|
* `childIndex` and `nodeId` tracking.
|
||||||
|
*/
|
||||||
|
bool constructAncestorPath(
|
||||||
|
const ShadowNode &rootShadowNode,
|
||||||
|
std::vector<std::reference_wrapper<const ShadowNode>> &ancestors) const;
|
||||||
|
|
||||||
#pragma mark - DebugStringConvertible
|
#pragma mark - DebugStringConvertible
|
||||||
|
|
||||||
#if RN_DEBUG_STRING_CONVERTIBLE
|
#if RN_DEBUG_STRING_CONVERTIBLE
|
||||||
|
@ -202,3 +202,78 @@ TEST(ShadowNodeTest, handleLocalData) {
|
|||||||
secondNode->sealRecursive();
|
secondNode->sealRecursive();
|
||||||
ASSERT_ANY_THROW(secondNode->setLocalData(localDataOver9000));
|
ASSERT_ANY_THROW(secondNode->setLocalData(localDataOver9000));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(ShadowNodeTest, handleBacktracking) {
|
||||||
|
/*
|
||||||
|
* The structure:
|
||||||
|
* <A>
|
||||||
|
* <AA/>
|
||||||
|
* <AB>
|
||||||
|
* <ABA/>
|
||||||
|
* <ABB/>
|
||||||
|
* <ABC/>
|
||||||
|
* </AB>
|
||||||
|
* <AC/>
|
||||||
|
* </A>
|
||||||
|
*/
|
||||||
|
|
||||||
|
auto props = std::make_shared<const TestProps>();
|
||||||
|
|
||||||
|
auto nodeAA = std::make_shared<TestShadowNode>(
|
||||||
|
ShadowNodeFragment{
|
||||||
|
.props = props,
|
||||||
|
.children = ShadowNode::emptySharedShadowNodeSharedList()},
|
||||||
|
nullptr);
|
||||||
|
|
||||||
|
auto nodeABA = std::make_shared<TestShadowNode>(
|
||||||
|
ShadowNodeFragment{
|
||||||
|
.props = props,
|
||||||
|
.children = ShadowNode::emptySharedShadowNodeSharedList()},
|
||||||
|
nullptr);
|
||||||
|
auto nodeABB = std::make_shared<TestShadowNode>(
|
||||||
|
ShadowNodeFragment{
|
||||||
|
.props = props,
|
||||||
|
.children = ShadowNode::emptySharedShadowNodeSharedList()},
|
||||||
|
nullptr);
|
||||||
|
auto nodeABC = std::make_shared<TestShadowNode>(
|
||||||
|
ShadowNodeFragment{
|
||||||
|
.props = props,
|
||||||
|
.children = ShadowNode::emptySharedShadowNodeSharedList()},
|
||||||
|
nullptr);
|
||||||
|
|
||||||
|
auto nodeABChildren = std::make_shared<std::vector<SharedShadowNode>>(
|
||||||
|
std::vector<SharedShadowNode>{nodeABA, nodeABB, nodeABC});
|
||||||
|
auto nodeAB = std::make_shared<TestShadowNode>(
|
||||||
|
ShadowNodeFragment{.props = props, .children = nodeABChildren}, nullptr);
|
||||||
|
|
||||||
|
auto nodeAC = std::make_shared<TestShadowNode>(
|
||||||
|
ShadowNodeFragment{
|
||||||
|
.props = props,
|
||||||
|
.children = ShadowNode::emptySharedShadowNodeSharedList()},
|
||||||
|
nullptr);
|
||||||
|
|
||||||
|
auto nodeAChildren = std::make_shared<std::vector<SharedShadowNode>>(
|
||||||
|
std::vector<SharedShadowNode>{nodeAA, nodeAB, nodeAC});
|
||||||
|
auto nodeA = std::make_shared<TestShadowNode>(
|
||||||
|
ShadowNodeFragment{.props = props, .children = nodeAChildren}, nullptr);
|
||||||
|
|
||||||
|
auto nodeZ = std::make_shared<TestShadowNode>(
|
||||||
|
ShadowNodeFragment{
|
||||||
|
.props = props,
|
||||||
|
.children = ShadowNode::emptySharedShadowNodeSharedList()},
|
||||||
|
nullptr);
|
||||||
|
|
||||||
|
std::vector<std::reference_wrapper<const ShadowNode>> ancestors = {};
|
||||||
|
|
||||||
|
// Negative case:
|
||||||
|
auto success = nodeZ->constructAncestorPath(*nodeA, ancestors);
|
||||||
|
ASSERT_FALSE(success);
|
||||||
|
ASSERT_EQ(ancestors.size(), 0);
|
||||||
|
|
||||||
|
// Positive case:
|
||||||
|
success = nodeABC->constructAncestorPath(*nodeA, ancestors);
|
||||||
|
ASSERT_TRUE(success);
|
||||||
|
ASSERT_EQ(ancestors.size(), 2);
|
||||||
|
ASSERT_EQ(&ancestors[0].get(), nodeAB.get());
|
||||||
|
ASSERT_EQ(&ancestors[1].get(), nodeA.get());
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user