mirror of
https://github.com/status-im/react-native.git
synced 2025-02-22 22:28:09 +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_);
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
#if RN_DEBUG_STRING_CONVERTIBLE
|
||||
|
@ -101,6 +101,21 @@ class ShadowNode : public virtual Sealable,
|
||||
*/
|
||||
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
|
||||
|
||||
#if RN_DEBUG_STRING_CONVERTIBLE
|
||||
|
@ -202,3 +202,78 @@ TEST(ShadowNodeTest, handleLocalData) {
|
||||
secondNode->sealRecursive();
|
||||
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