From 7d1d4dc0645a5dfecc53d05b16338f9c08cc0d0f Mon Sep 17 00:00:00 2001 From: Joshua Gross Date: Mon, 7 Jun 2021 17:10:45 -0700 Subject: [PATCH] Ship new C++ Differ in code Summary: The new C++ Differ has been validated on Android and iOS. Delete the old code path. Changelog: [Internal] Reviewed By: sammy-SC Differential Revision: D28904330 fbshipit-source-id: 2e0d8682f6b2a79f9758ed8b7b92809060835815 --- .../animations/tests/LayoutAnimationTest.cpp | 4 +- .../renderer/mounting/Differentiator.cpp | 9 +- .../react/renderer/mounting/Differentiator.h | 3 +- .../DifferentiatorFlatteningClassic.cpp | 1564 ----------------- .../DifferentiatorFlatteningClassic.h | 45 - .../renderer/mounting/MountingCoordinator.cpp | 8 +- .../renderer/mounting/MountingCoordinator.h | 4 - .../react/renderer/mounting/ShadowTree.cpp | 4 +- .../react/renderer/mounting/ShadowTree.h | 3 +- ReactCommon/react/renderer/mounting/stubs.cpp | 2 +- .../renderer/mounting/tests/MountingTest.cpp | 30 +- .../tests/ShadowTreeLifeCycleTest.cpp | 8 +- .../mounting/tests/StackingContextTest.cpp | 4 +- .../tests/StateReconciliationTest.cpp | 6 +- .../react/renderer/scheduler/Scheduler.cpp | 4 - .../react/renderer/scheduler/Scheduler.h | 1 - .../renderer/scheduler/SurfaceHandler.cpp | 8 +- .../react/renderer/scheduler/SurfaceHandler.h | 8 - 18 files changed, 26 insertions(+), 1689 deletions(-) delete mode 100644 ReactCommon/react/renderer/mounting/DifferentiatorFlatteningClassic.cpp delete mode 100644 ReactCommon/react/renderer/mounting/DifferentiatorFlatteningClassic.h diff --git a/ReactCommon/react/renderer/animations/tests/LayoutAnimationTest.cpp b/ReactCommon/react/renderer/animations/tests/LayoutAnimationTest.cpp index f2ab0d4082..5529ec9eec 100644 --- a/ReactCommon/react/renderer/animations/tests/LayoutAnimationTest.cpp +++ b/ReactCommon/react/renderer/animations/tests/LayoutAnimationTest.cpp @@ -124,7 +124,7 @@ static void testShadowNodeTreeLifeCycleLayoutAnimations( // Building an initial view hierarchy. auto viewTree = buildStubViewTreeWithoutUsingDifferentiator(*emptyRootNode); viewTree.mutate( - calculateShadowViewMutations(*emptyRootNode, *currentRootNode, true)); + calculateShadowViewMutations(*emptyRootNode, *currentRootNode)); for (int j = 0; j < stages; j++) { auto nextRootNode = currentRootNode; @@ -151,7 +151,7 @@ static void testShadowNodeTreeLifeCycleLayoutAnimations( // Calculating mutations. auto originalMutations = - calculateShadowViewMutations(*currentRootNode, *nextRootNode, true); + calculateShadowViewMutations(*currentRootNode, *nextRootNode); // If tree randomization produced no changes in the form of mutations, // don't bother trying to animate because this violates a bunch of our diff --git a/ReactCommon/react/renderer/mounting/Differentiator.cpp b/ReactCommon/react/renderer/mounting/Differentiator.cpp index 2773cd49e4..a37e90758f 100644 --- a/ReactCommon/react/renderer/mounting/Differentiator.cpp +++ b/ReactCommon/react/renderer/mounting/Differentiator.cpp @@ -6,7 +6,6 @@ */ #include "Differentiator.h" -#include "DifferentiatorFlatteningClassic.h" #include #include @@ -1658,13 +1657,7 @@ ShadowViewNodePair::OwningList sliceChildShadowNodeViewPairsLegacy( ShadowViewMutation::List calculateShadowViewMutations( ShadowNode const &oldRootShadowNode, - ShadowNode const &newRootShadowNode, - bool useNewDiffer) { - if (!useNewDiffer) { - return DifferOld::calculateShadowViewMutations( - oldRootShadowNode, newRootShadowNode); - } - + ShadowNode const &newRootShadowNode) { SystraceSection s("calculateShadowViewMutations"); // Root shadow nodes must be belong the same family. diff --git a/ReactCommon/react/renderer/mounting/Differentiator.h b/ReactCommon/react/renderer/mounting/Differentiator.h index eef837de61..551173652c 100644 --- a/ReactCommon/react/renderer/mounting/Differentiator.h +++ b/ReactCommon/react/renderer/mounting/Differentiator.h @@ -47,8 +47,7 @@ using ViewNodePairScope = std::deque; */ ShadowViewMutation::List calculateShadowViewMutations( ShadowNode const &oldRootShadowNode, - ShadowNode const &newRootShadowNode, - bool useNewDiffer); + ShadowNode const &newRootShadowNode); /** * Generates a list of `ShadowViewNodePair`s that represents a layer of a diff --git a/ReactCommon/react/renderer/mounting/DifferentiatorFlatteningClassic.cpp b/ReactCommon/react/renderer/mounting/DifferentiatorFlatteningClassic.cpp deleted file mode 100644 index d81b70cfd4..0000000000 --- a/ReactCommon/react/renderer/mounting/DifferentiatorFlatteningClassic.cpp +++ /dev/null @@ -1,1564 +0,0 @@ -/* - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include "DifferentiatorFlatteningClassic.h" - -#include -#include -#include -#include -#include -#include -#include "ShadowView.h" - -#ifdef DEBUG_LOGS_DIFFER -#include -#define DEBUG_LOGS_BREADCRUMBS 1 -#define DEBUG_LOGS(code) code -#else -#define DEBUG_LOGS(code) -#endif - -#ifdef DEBUG_LOGS_BREADCRUMBS -#define BREADCRUMB_TYPE std::string -#define DIFF_BREADCRUMB(X) (breadcrumb + " - " + std::string(X)) -#define CREATE_DIFF_BREADCRUMB(X) std::to_string(X) -#else - -enum class NoBreadcrumb {}; - -#define BREADCRUMB_TYPE NoBreadcrumb const & -#define DIFF_BREADCRUMB(X) \ - {} -#define CREATE_DIFF_BREADCRUMB(X) \ - {} -#endif - -namespace facebook { -namespace react { -namespace DifferOld { - -/* - * Extremely simple and naive implementation of a map. - * The map is simple but it's optimized for particular constraints that we have - * here. - * - * A regular map implementation (e.g. `std::unordered_map`) has some basic - * performance guarantees like constant average insertion and lookup complexity. - * This is nice, but it's *average* complexity measured on a non-trivial amount - * of data. The regular map is a very complex data structure that using hashing, - * buckets, multiple comprising operations, multiple allocations and so on. - * - * In our particular case, we need a map for `int` to `void *` with a dozen - * values. In these conditions, nothing can beat a naive implementation using a - * stack-allocated vector. And this implementation is exactly this: no - * allocation, no hashing, no complex branching, no buckets, no iterators, no - * rehashing, no other guarantees. It's crazy limited, unsafe, and performant on - * a trivial amount of data. - * - * Besides that, we also need to optimize for insertion performance (the case - * where a bunch of views appears on the screen first time); in this - * implementation, this is as performant as vector `push_back`. - */ -template -class TinyMap final { - public: - using Pair = std::pair; - using Iterator = Pair *; - - /** - * This must strictly only be called from outside of this class. - */ - inline Iterator begin() { - // Force a clean so that iterating over this TinyMap doesn't iterate over - // erased elements. If all elements erased are at the front of the vector, - // then we don't need to clean. - cleanVector(erasedAtFront_ != numErased_); - - Iterator it = begin_(); - - if (it != nullptr) { - return it + erasedAtFront_; - } - - return nullptr; - } - - inline Iterator end() { - // `back()` asserts on the vector being non-empty - if (vector_.empty() || numErased_ == vector_.size()) { - return nullptr; - } - - return &vector_.back() + 1; - } - - inline Iterator find(KeyT key) { - cleanVector(); - - react_native_assert(key != 0); - - if (begin_() == nullptr) { - return end(); - } - - for (auto it = begin_() + erasedAtFront_; it != end(); it++) { - if (it->first == key) { - return it; - } - } - - return end(); - } - - inline void insert(Pair pair) { - react_native_assert(pair.first != 0); - vector_.push_back(pair); - } - - inline void erase(Iterator iterator) { - // Invalidate tag. - iterator->first = 0; - - if (iterator == begin_() + erasedAtFront_) { - erasedAtFront_++; - } - - numErased_++; - } - - private: - /** - * Same as begin() but doesn't call cleanVector at the beginning. - */ - inline Iterator begin_() { - // `front()` asserts on the vector being non-empty - if (vector_.empty() || vector_.size() == numErased_) { - return nullptr; - } - - return &vector_.front(); - } - - /** - * Remove erased elements from internal vector. - * We only modify the vector if erased elements are at least half of the - * vector. - */ - inline void cleanVector(bool forceClean = false) { - if ((numErased_ < (vector_.size() / 2) && !forceClean) || vector_.empty() || - numErased_ == 0 || numErased_ == erasedAtFront_) { - return; - } - - if (numErased_ == vector_.size()) { - vector_.clear(); - } else { - vector_.erase( - std::remove_if( - vector_.begin(), - vector_.end(), - [](auto const &item) { return item.first == 0; }), - vector_.end()); - } - numErased_ = 0; - erasedAtFront_ = 0; - } - - better::small_vector vector_; - int numErased_{0}; - int erasedAtFront_{0}; -}; - -/* - * Sorting comparator for `reorderInPlaceIfNeeded`. - */ -static bool shouldFirstPairComesBeforeSecondOne( - ShadowViewNodePairLegacy const &lhs, - ShadowViewNodePairLegacy const &rhs) noexcept { - return lhs.shadowNode->getOrderIndex() < rhs.shadowNode->getOrderIndex(); -} - -/* - * Reorders pairs in-place based on `orderIndex` using a stable sort algorithm. - */ -static void reorderInPlaceIfNeeded( - ShadowViewNodePairLegacy::OwningList &pairs) noexcept { - if (pairs.size() < 2) { - return; - } - - auto isReorderNeeded = false; - for (auto const &pair : pairs) { - if (pair.shadowNode->getOrderIndex() != 0) { - isReorderNeeded = true; - break; - } - } - - if (!isReorderNeeded) { - return; - } - - std::stable_sort( - pairs.begin(), pairs.end(), &shouldFirstPairComesBeforeSecondOne); -} - -static void sliceChildShadowNodeViewPairsRecursivelyV2( - ShadowViewNodePairLegacy::OwningList &pairList, - Point layoutOffset, - ShadowNode const &shadowNode) { - for (auto const &sharedChildShadowNode : shadowNode.getChildren()) { - auto &childShadowNode = *sharedChildShadowNode; - -#ifndef ANDROID - // Temporary disabled on Android because the mounting infrastructure - // is not fully ready yet. - if (childShadowNode.getTraits().check(ShadowNodeTraits::Trait::Hidden)) { - continue; - } -#endif - - auto shadowView = ShadowView(childShadowNode); - auto origin = layoutOffset; - if (shadowView.layoutMetrics != EmptyLayoutMetrics) { - origin += shadowView.layoutMetrics.frame.origin; - shadowView.layoutMetrics.frame.origin += layoutOffset; - } - - // This might not be a FormsView, or a FormsStackingContext. We let the - // differ handle removal of flattened views from the Mounting layer and - // shuffling their children around. - bool isConcreteView = - childShadowNode.getTraits().check(ShadowNodeTraits::Trait::FormsView); - bool areChildrenFlattened = !childShadowNode.getTraits().check( - ShadowNodeTraits::Trait::FormsStackingContext); - pairList.push_back( - {shadowView, &childShadowNode, areChildrenFlattened, isConcreteView}); - - if (!childShadowNode.getTraits().check( - ShadowNodeTraits::Trait::FormsStackingContext)) { - sliceChildShadowNodeViewPairsRecursivelyV2( - pairList, origin, childShadowNode); - } - } -} - -ShadowViewNodePairLegacy::OwningList sliceChildShadowNodeViewPairsV2( - ShadowNode const &shadowNode, - bool allowFlattened) { - auto pairList = ShadowViewNodePairLegacy::OwningList{}; - - if (!shadowNode.getTraits().check( - ShadowNodeTraits::Trait::FormsStackingContext) && - shadowNode.getTraits().check(ShadowNodeTraits::Trait::FormsView) && - !allowFlattened) { - return pairList; - } - - sliceChildShadowNodeViewPairsRecursivelyV2(pairList, {0, 0}, shadowNode); - - // Sorting pairs based on `orderIndex` if needed. - reorderInPlaceIfNeeded(pairList); - - // Set list and mountIndex for each after reordering - size_t mountIndex = 0; - for (auto &child : pairList) { - child.mountIndex = (child.isConcreteView ? mountIndex++ : -1); - } - - return pairList; -} - -/* - * Before we start to diff, let's make sure all our core data structures are in - * good shape to deliver the best performance. - */ -static_assert( - std::is_move_constructible::value, - "`ShadowViewMutation` must be `move constructible`."); -static_assert( - std::is_move_constructible::value, - "`ShadowView` must be `move constructible`."); -static_assert( - std::is_move_constructible::value, - "`ShadowViewNodePairLegacy` must be `move constructible`."); -static_assert( - std::is_move_constructible::value, - "`ShadowViewNodePairLegacy::OwningList` must be `move constructible`."); - -static_assert( - std::is_move_assignable::value, - "`ShadowViewMutation` must be `move assignable`."); -static_assert( - std::is_move_assignable::value, - "`ShadowView` must be `move assignable`."); -static_assert( - std::is_move_assignable::value, - "`ShadowViewNodePairLegacy` must be `move assignable`."); -static_assert( - std::is_move_assignable::value, - "`ShadowViewNodePairLegacy::OwningList` must be `move assignable`."); - -// Forward declaration -static void calculateShadowViewMutationsV2( - BREADCRUMB_TYPE breadcrumb, - ShadowViewMutation::List &mutations, - ShadowView const &parentShadowView, - ShadowViewNodePairLegacy::OwningList &&oldChildPairs, - ShadowViewNodePairLegacy::OwningList &&newChildPairs); - -struct OrderedMutationInstructionContainer { - ShadowViewMutation::List &createMutations; - ShadowViewMutation::List &deleteMutations; - ShadowViewMutation::List &insertMutations; - ShadowViewMutation::List &removeMutations; - ShadowViewMutation::List &updateMutations; - ShadowViewMutation::List &downwardMutations; - ShadowViewMutation::List &destructiveDownwardMutations; -}; - -static void calculateShadowViewMutationsFlattener( - BREADCRUMB_TYPE breadcrumb, - ReparentMode reparentMode, - OrderedMutationInstructionContainer &mutationInstructionContainer, - ShadowView const &parentShadowView, - TinyMap &unvisitedFlattenedNodes, - ShadowViewNodePairLegacy const &node, - TinyMap *parentSubVisitedOtherNewNodes = - nullptr, - TinyMap *parentSubVisitedOtherOldNodes = - nullptr); - -/** - * Here we flatten or unflatten a subtree, given an unflattened node in either - * the old or new tree, and a list of flattened nodes in the other tree. - * - * For example: if you are Flattening, the node will be in the old tree and the - * list will be from the new tree. If you are Unflattening, the opposite is - true. - - * It is currently not possible for ReactJS, and therefore React Native, to move - * a node *from* one parent to another without an entirely new subtree being - * created. When we "reparent" in React Native here it is only because - intermediate - * ShadowNodes/ShadowViews, which *always* exist, are flattened or unflattened - away. - * Thus, this algorithm handles the very specialized cases of the tree - collapsing or - * expanding vertically in that way. - - * Sketch of algorithm: - * 0. Create a map of nodes in the flattened list. This should be done *before* - * calling this function. - * 1. Traverse the Node Subtree; remove elements from the map as they are - * visited in the tree. - * Perform a Remove/Insert depending on if we're flattening or unflattening - * If Tree node is not in Map/List, perform Delete/Create. - * 2. Traverse the list. - * Perform linear remove from the old View, or insert into the new parent - * View if we're flattening. - * If a node is in the list but not the map, it means it's been visited and - * Update has already been - * performed in the subtree. If it *is* in the map, it means the node is not - * * in the Tree, and should be Deleted/Created - * **after this function is called**, by the caller. - */ -static void calculateShadowViewMutationsFlattener( - BREADCRUMB_TYPE breadcrumb, - ReparentMode reparentMode, - OrderedMutationInstructionContainer &mutationInstructionContainer, - ShadowView const &parentShadowView, - TinyMap &unvisitedOtherNodes, - ShadowViewNodePairLegacy const &node, - TinyMap *parentSubVisitedOtherNewNodes, - TinyMap *parentSubVisitedOtherOldNodes) { - DEBUG_LOGS({ - LOG(ERROR) << "Differ Flattener 1: " - << (reparentMode == ReparentMode::Unflatten ? "Unflattening" - : "Flattening") - << " [" << node.shadowView.tag << "]"; - }); - - // Step 1: iterate through entire tree - ShadowViewNodePairLegacy::OwningList treeChildren = - sliceChildShadowNodeViewPairsV2(*node.shadowNode); - - DEBUG_LOGS({ - LOG(ERROR) << "Differ Flattener 1.4: " - << (reparentMode == ReparentMode::Unflatten ? "Unflattening" - : "Flattening") - << " [" << node.shadowView.tag << "]"; - LOG(ERROR) << "Differ Flattener Entry: Child Pairs: "; - std::string strTreeChildPairs; - for (size_t k = 0; k < treeChildren.size(); k++) { - strTreeChildPairs.append(std::to_string(treeChildren[k].shadowView.tag)); - strTreeChildPairs.append(treeChildren[k].isConcreteView ? "" : "'"); - strTreeChildPairs.append(treeChildren[k].flattened ? "*" : ""); - strTreeChildPairs.append(", "); - } - std::string strListChildPairs; - for (auto &unvisitedNode : unvisitedOtherNodes) { - strListChildPairs.append( - std::to_string(unvisitedNode.second->shadowView.tag)); - strListChildPairs.append(unvisitedNode.second->isConcreteView ? "" : "'"); - strListChildPairs.append(unvisitedNode.second->flattened ? "*" : ""); - strListChildPairs.append(", "); - } - LOG(ERROR) << "Differ Flattener Entry: Tree Child Pairs: " - << strTreeChildPairs; - LOG(ERROR) << "Differ Flattener Entry: List Child Pairs: " - << strListChildPairs; - }); - - // Views in other tree that are visited by sub-flattening or sub-unflattening - TinyMap subVisitedOtherNewNodes{}; - TinyMap subVisitedOtherOldNodes{}; - auto subVisitedNewMap = - (parentSubVisitedOtherNewNodes != nullptr ? parentSubVisitedOtherNewNodes - : &subVisitedOtherNewNodes); - auto subVisitedOldMap = - (parentSubVisitedOtherOldNodes != nullptr ? parentSubVisitedOtherOldNodes - : &subVisitedOtherOldNodes); - - // Candidates for full tree creation or deletion at the end of this function - auto deletionCreationCandidatePairs = - TinyMap{}; - - for (size_t index = 0; - index < treeChildren.size() && index < treeChildren.size(); - index++) { - // First, remove all children of the tree being flattened, or insert - // children into parent tree if they're being unflattened. Then, look up - // each node in the "unvisited" list and update the nodes and subtrees if - // appropriate. - auto &treeChildPair = treeChildren[index]; - - // Caller will take care of the corresponding action in the other tree. - if (treeChildPair.isConcreteView) { - if (reparentMode == ReparentMode::Flatten) { - mutationInstructionContainer.removeMutations.push_back( - ShadowViewMutation::RemoveMutation( - node.shadowView, - treeChildPair.shadowView, - static_cast(treeChildPair.mountIndex))); - } else { - mutationInstructionContainer.insertMutations.push_back( - ShadowViewMutation::InsertMutation( - node.shadowView, - treeChildPair.shadowView, - static_cast(treeChildPair.mountIndex))); - } - } - - // Try to find node in other tree - auto unvisitedIt = unvisitedOtherNodes.find(treeChildPair.shadowView.tag); - auto subVisitedOtherNewIt = - (unvisitedIt == unvisitedOtherNodes.end() - ? subVisitedNewMap->find(treeChildPair.shadowView.tag) - : subVisitedNewMap->end()); - auto subVisitedOtherOldIt = - (unvisitedIt == unvisitedOtherNodes.end() - ? subVisitedOldMap->find(treeChildPair.shadowView.tag) - : subVisitedOldMap->end()); - - // Find in other tree - if (unvisitedIt != unvisitedOtherNodes.end() || - subVisitedOtherNewIt != subVisitedNewMap->end() || - subVisitedOtherOldIt != subVisitedOldMap->end()) { - // If we've already done updates on this node, don't repeat. - if (reparentMode == ReparentMode::Flatten && - unvisitedIt == unvisitedOtherNodes.end() && - subVisitedOtherOldIt != subVisitedOldMap->end()) { - continue; - } else if ( - reparentMode == ReparentMode::Unflatten && - unvisitedIt == unvisitedOtherNodes.end() && - subVisitedOtherNewIt != subVisitedNewMap->end()) { - continue; - } - - auto &otherTreeNodePair = - *(unvisitedIt != unvisitedOtherNodes.end() - ? unvisitedIt->second - : (subVisitedOtherNewIt != subVisitedNewMap->end() - ? subVisitedOtherNewIt->second - : subVisitedOtherOldIt->second)); - - // If we've already done updates, don't repeat it. - if (treeChildPair.inOtherTree || otherTreeNodePair.inOtherTree) { - continue; - } - - auto &newTreeNodePair = - (reparentMode == ReparentMode::Flatten ? otherTreeNodePair - : treeChildPair); - auto &oldTreeNodePair = - (reparentMode == ReparentMode::Flatten ? treeChildPair - : otherTreeNodePair); - - if (newTreeNodePair.shadowView != oldTreeNodePair.shadowView && - newTreeNodePair.isConcreteView && oldTreeNodePair.isConcreteView) { - mutationInstructionContainer.updateMutations.push_back( - ShadowViewMutation::UpdateMutation( - oldTreeNodePair.shadowView, newTreeNodePair.shadowView)); - } - - // Update children if appropriate. - if (!oldTreeNodePair.flattened && !newTreeNodePair.flattened) { - if (oldTreeNodePair.shadowNode != newTreeNodePair.shadowNode) { - calculateShadowViewMutationsV2( - DIFF_BREADCRUMB( - "(Un)Flattener trivial update of " + - std::to_string(newTreeNodePair.shadowView.tag)), - mutationInstructionContainer.downwardMutations, - newTreeNodePair.shadowView, - sliceChildShadowNodeViewPairsV2(*oldTreeNodePair.shadowNode), - sliceChildShadowNodeViewPairsV2(*newTreeNodePair.shadowNode)); - } - } else if (oldTreeNodePair.flattened != newTreeNodePair.flattened) { - // We need to handle one of the children being flattened or unflattened, - // in the context of a parent flattening or unflattening. - ReparentMode childReparentMode = - (oldTreeNodePair.flattened ? ReparentMode::Unflatten - : ReparentMode::Flatten); - - // Case 1: child mode is the same as parent. - // This is a flatten-flatten, or unflatten-unflatten. - if (childReparentMode == reparentMode) { - calculateShadowViewMutationsFlattener( - DIFF_BREADCRUMB( - std::string( - reparentMode == ReparentMode::Flatten - ? "Flatten-Flatten" - : "Unflatten-Unflatten") + - " new:" + - std::to_string( - reparentMode == ReparentMode::Flatten - ? parentShadowView.tag - : newTreeNodePair.shadowView.tag) + - " old:" + std::to_string(treeChildPair.shadowView.tag)), - childReparentMode, - mutationInstructionContainer, - (reparentMode == ReparentMode::Flatten - ? parentShadowView - : newTreeNodePair.shadowView), - unvisitedOtherNodes, - treeChildPair, - subVisitedNewMap, - subVisitedOldMap); - } else { - // Unflatten parent, flatten child - if (childReparentMode == ReparentMode::Flatten) { - // Construct unvisited nodes map - auto unvisitedNewChildPairs = - TinyMap{}; - // Memory note: these oldFlattenedNodes all disappear at the end of - // this "else" block, including any annotations we put on them. - auto newFlattenedNodes = sliceChildShadowNodeViewPairsV2( - *newTreeNodePair.shadowNode, true); - for (size_t i = 0; i < newFlattenedNodes.size(); i++) { - auto &newChild = newFlattenedNodes[i]; - - auto unvisitedOtherNodesIt = - unvisitedOtherNodes.find(newChild.shadowView.tag); - if (unvisitedOtherNodesIt != unvisitedOtherNodes.end()) { - auto &unvisitedItPair = *unvisitedOtherNodesIt->second; - unvisitedNewChildPairs.insert( - {unvisitedItPair.shadowView.tag, &unvisitedItPair}); - } else { - unvisitedNewChildPairs.insert( - {newChild.shadowView.tag, &newChild}); - } - } - - // Flatten old tree into new list - // At the end of this loop we still want to know which of these - // children are visited, so we reuse the `newRemainingPairs` map. - calculateShadowViewMutationsFlattener( - DIFF_BREADCRUMB( - std::string("Flatten old tree into new list; new:") + - std::to_string( - reparentMode == ReparentMode::Flatten - ? parentShadowView.tag - : newTreeNodePair.shadowView.tag) + - " old:" + std::to_string(oldTreeNodePair.shadowView.tag)), - ReparentMode::Flatten, - mutationInstructionContainer, - (reparentMode == ReparentMode::Flatten - ? parentShadowView - : newTreeNodePair.shadowView), - unvisitedNewChildPairs, - oldTreeNodePair, - subVisitedNewMap, - subVisitedOldMap); - - for (auto &newFlattenedNode : newFlattenedNodes) { - auto unvisitedOldChildPairIt = - unvisitedNewChildPairs.find(newFlattenedNode.shadowView.tag); - - if (unvisitedOldChildPairIt == unvisitedNewChildPairs.end()) { - // Node was visited. - - auto deleteCreateIt = deletionCreationCandidatePairs.find( - newFlattenedNode.shadowView.tag); - if (deleteCreateIt != deletionCreationCandidatePairs.end()) { - deletionCreationCandidatePairs.erase(deleteCreateIt); - } - } - } - } - // Flatten parent, unflatten child - else { - // Construct unvisited nodes map - auto unvisitedOldChildPairs = - TinyMap{}; - // Memory note: these oldFlattenedNodes all disappear at the end of - // this "else" block, including any annotations we put on them. - auto oldFlattenedNodes = sliceChildShadowNodeViewPairsV2( - *oldTreeNodePair.shadowNode, true); - for (size_t i = 0; i < oldFlattenedNodes.size(); i++) { - auto &oldChild = oldFlattenedNodes[i]; - - auto unvisitedOtherNodesIt = - unvisitedOtherNodes.find(oldChild.shadowView.tag); - if (unvisitedOtherNodesIt != unvisitedOtherNodes.end()) { - auto &unvisitedItPair = *unvisitedOtherNodesIt->second; - unvisitedOldChildPairs.insert( - {unvisitedItPair.shadowView.tag, &unvisitedItPair}); - } else { - unvisitedOldChildPairs.insert( - {oldChild.shadowView.tag, &oldChild}); - } - } - - // Unflatten old list into new tree - calculateShadowViewMutationsFlattener( - DIFF_BREADCRUMB( - "Unflatten old list into new tree; old:" + - std::to_string( - reparentMode == ReparentMode::Flatten - ? parentShadowView.tag - : newTreeNodePair.shadowView.tag) + - " new:" + std::to_string(newTreeNodePair.shadowView.tag)), - ReparentMode::Unflatten, - mutationInstructionContainer, - (reparentMode == ReparentMode::Flatten - ? parentShadowView - : newTreeNodePair.shadowView), - unvisitedOldChildPairs, - newTreeNodePair, - subVisitedNewMap, - subVisitedOldMap); - - // If old nodes were not visited, we know that we can delete them - // now. They will be removed from the hierarchy by the outermost - // loop of this function. - for (auto &oldFlattenedNode : oldFlattenedNodes) { - auto unvisitedOldChildPairIt = - unvisitedOldChildPairs.find(oldFlattenedNode.shadowView.tag); - if (unvisitedOldChildPairIt != unvisitedOldChildPairs.end()) { - // Node unvisited - mark the entire subtree for deletion - if (oldFlattenedNode.isConcreteView) { - auto tag = oldFlattenedNode.shadowView.tag; - auto oldRemainingChildInListIt = std::find_if( - treeChildren.begin(), - treeChildren.end(), - [&tag](ShadowViewNodePairLegacy &nodePair) { - return nodePair.shadowView.tag == tag; - }); - if (oldRemainingChildInListIt != treeChildren.end()) { - auto deleteCreateIt = deletionCreationCandidatePairs.find( - oldFlattenedNode.shadowView.tag); - if (deleteCreateIt == - deletionCreationCandidatePairs.end()) { - deletionCreationCandidatePairs.insert( - {tag, &*oldRemainingChildInListIt}); - } - } else { - // TODO: we might want to remove this block. It seems - // impossible to hit this logically (and empirically, after - // testing on lots of randomized and pathologically - // constructed trees) but I'm leaving this here out of an - // abundance of caution. - // In theory, this path should never be hit. If we don't see - // this in dev after a few months, let's delete this path. - react_native_assert(false); - mutationInstructionContainer.deleteMutations.push_back( - ShadowViewMutation::DeleteMutation( - oldFlattenedNode.shadowView)); - - calculateShadowViewMutationsV2( - DIFF_BREADCRUMB( - "Destroy " + - std::to_string(oldFlattenedNode.shadowView.tag)), - mutationInstructionContainer - .destructiveDownwardMutations, - oldFlattenedNode.shadowView, - sliceChildShadowNodeViewPairsV2( - *oldFlattenedNode.shadowNode), - {}); - } - } - } else { - // Node was visited - make sure to remove it from - // "newRemainingPairs" map - auto newRemainingIt = - unvisitedOtherNodes.find(oldFlattenedNode.shadowView.tag); - if (newRemainingIt != unvisitedOtherNodes.end()) { - unvisitedOtherNodes.erase(newRemainingIt); - } - - // We also remove it from delete/creation candidates - auto deleteCreateIt = deletionCreationCandidatePairs.find( - oldFlattenedNode.shadowView.tag); - if (deleteCreateIt != deletionCreationCandidatePairs.end()) { - deletionCreationCandidatePairs.erase(deleteCreateIt); - } - } - } - } - } - } - - // Mark that node exists in another tree, but only if the tree node is a - // concrete view. Removing the node from the unvisited list prevents the - // caller from taking further action on this node, so make sure to - // delete/create if the Concreteness of the node has changed. - if (newTreeNodePair.isConcreteView != oldTreeNodePair.isConcreteView && - !newTreeNodePair.inOtherTree) { - if (newTreeNodePair.isConcreteView) { - mutationInstructionContainer.createMutations.push_back( - ShadowViewMutation::CreateMutation(newTreeNodePair.shadowView)); - } else { - mutationInstructionContainer.deleteMutations.push_back( - ShadowViewMutation::DeleteMutation(newTreeNodePair.shadowView)); - } - } - - treeChildPair.inOtherTree = true; - otherTreeNodePair.inOtherTree = true; - - if (parentSubVisitedOtherNewNodes != nullptr) { - parentSubVisitedOtherNewNodes->insert( - {newTreeNodePair.shadowView.tag, &newTreeNodePair}); - } - if (parentSubVisitedOtherOldNodes != nullptr) { - parentSubVisitedOtherOldNodes->insert( - {oldTreeNodePair.shadowView.tag, &oldTreeNodePair}); - } - - if (unvisitedIt != unvisitedOtherNodes.end()) { - unvisitedOtherNodes.erase(unvisitedIt); - } - } else { - // Node does not in exist in other tree. - if (treeChildPair.isConcreteView && !treeChildPair.inOtherTree) { - auto deletionCreationIt = - deletionCreationCandidatePairs.find(treeChildPair.shadowView.tag); - if (deletionCreationIt == deletionCreationCandidatePairs.end()) { - deletionCreationCandidatePairs.insert( - {treeChildPair.shadowView.tag, &treeChildPair}); - } - } - } - } - - // Final step: go through creation/deletion candidates and delete/create - // subtrees if they were never visited during the execution of the above loop - // and recursions. - for (auto it = deletionCreationCandidatePairs.begin(); - it != deletionCreationCandidatePairs.end(); - it++) { - if (it->first == 0) { - continue; - } - auto &treeChildPair = *it->second; - - // If node was visited during a flattening/unflattening recursion. - if (treeChildPair.inOtherTree) { - continue; - } - - if (reparentMode == ReparentMode::Flatten) { - mutationInstructionContainer.deleteMutations.push_back( - ShadowViewMutation::DeleteMutation(treeChildPair.shadowView)); - - if (!treeChildPair.flattened) { - calculateShadowViewMutationsV2( - DIFF_BREADCRUMB( - "Recursively delete tree child pair (flatten case): " + - std::to_string(treeChildPair.shadowView.tag)), - mutationInstructionContainer.destructiveDownwardMutations, - treeChildPair.shadowView, - sliceChildShadowNodeViewPairsV2(*treeChildPair.shadowNode), - {}); - } - } else { - mutationInstructionContainer.createMutations.push_back( - ShadowViewMutation::CreateMutation(treeChildPair.shadowView)); - - if (!treeChildPair.flattened) { - calculateShadowViewMutationsV2( - DIFF_BREADCRUMB( - "Recursively delete tree child pair (unflatten case): " + - std::to_string(treeChildPair.shadowView.tag)), - mutationInstructionContainer.downwardMutations, - treeChildPair.shadowView, - {}, - sliceChildShadowNodeViewPairsV2(*treeChildPair.shadowNode)); - } - } - } -} - -static void calculateShadowViewMutationsV2( - BREADCRUMB_TYPE breadcrumb, - ShadowViewMutation::List &mutations, - ShadowView const &parentShadowView, - ShadowViewNodePairLegacy::OwningList &&oldChildPairs, - ShadowViewNodePairLegacy::OwningList &&newChildPairs) { - if (oldChildPairs.empty() && newChildPairs.empty()) { - return; - } - - size_t index = 0; - - // Lists of mutations - auto createMutations = ShadowViewMutation::List{}; - auto deleteMutations = ShadowViewMutation::List{}; - auto insertMutations = ShadowViewMutation::List{}; - auto removeMutations = ShadowViewMutation::List{}; - auto updateMutations = ShadowViewMutation::List{}; - auto downwardMutations = ShadowViewMutation::List{}; - auto destructiveDownwardMutations = ShadowViewMutation::List{}; - auto mutationInstructionContainer = OrderedMutationInstructionContainer{ - createMutations, - deleteMutations, - insertMutations, - removeMutations, - updateMutations, - downwardMutations, - destructiveDownwardMutations}; - - DEBUG_LOGS({ - LOG(ERROR) << "Differ Entry: Child Pairs of node: [" << parentShadowView.tag - << "]"; - std::string strOldChildPairs; - for (size_t oldIndex = 0; oldIndex < oldChildPairs.size(); oldIndex++) { - strOldChildPairs.append( - std::to_string(oldChildPairs[oldIndex].shadowView.tag)); - strOldChildPairs.append( - oldChildPairs[oldIndex].isConcreteView ? "" : "'"); - strOldChildPairs.append(oldChildPairs[oldIndex].flattened ? "*" : ""); - strOldChildPairs.append(", "); - } - std::string strNewChildPairs; - for (size_t newIndex = 0; newIndex < newChildPairs.size(); newIndex++) { - strNewChildPairs.append( - std::to_string(newChildPairs[newIndex].shadowView.tag)); - strNewChildPairs.append( - newChildPairs[newIndex].isConcreteView ? "" : "'"); - strNewChildPairs.append(newChildPairs[newIndex].flattened ? "*" : ""); - strNewChildPairs.append(", "); - } - LOG(ERROR) << "Differ Entry: Old Child Pairs: " << strOldChildPairs; - LOG(ERROR) << "Differ Entry: New Child Pairs: " << strNewChildPairs; - }); - - // Stage 1: Collecting `Update` mutations - for (index = 0; index < oldChildPairs.size() && index < newChildPairs.size(); - index++) { - auto &oldChildPair = oldChildPairs[index]; - auto &newChildPair = newChildPairs[index]; - - if (oldChildPair.shadowView.tag != newChildPair.shadowView.tag) { - DEBUG_LOGS({ - LOG(ERROR) << "Differ Branch 1.1: Tags Different: [" - << oldChildPair.shadowView.tag << "] [" - << newChildPair.shadowView.tag << "]" - << " with parent: [" << parentShadowView.tag << "]"; - }); - - // Totally different nodes, updating is impossible. - break; - } - - // If either view was flattened, and that has changed this frame, don't try - // to update - if (oldChildPair.flattened != newChildPair.flattened || - oldChildPair.isConcreteView != newChildPair.isConcreteView) { - break; - } - - DEBUG_LOGS({ - LOG(ERROR) << "Differ Branch 1.2: Same tags, update and recurse: [" - << oldChildPair.shadowView.tag << "]" - << (oldChildPair.flattened ? " (flattened)" : "") - << (oldChildPair.isConcreteView ? " (concrete)" : "") << "[" - << newChildPair.shadowView.tag << "]" - << (newChildPair.flattened ? " (flattened)" : "") - << (newChildPair.isConcreteView ? " (concrete)" : "") - << " with parent: [" << parentShadowView.tag << "]"; - }); - - if (newChildPair.isConcreteView && - oldChildPair.shadowView != newChildPair.shadowView) { - updateMutations.push_back(ShadowViewMutation::UpdateMutation( - oldChildPair.shadowView, newChildPair.shadowView)); - } - - // Recursively update tree if ShadowNode pointers are not equal - if (!oldChildPair.flattened && - oldChildPair.shadowNode != newChildPair.shadowNode) { - auto oldGrandChildPairs = - sliceChildShadowNodeViewPairsV2(*oldChildPair.shadowNode); - auto newGrandChildPairs = - sliceChildShadowNodeViewPairsV2(*newChildPair.shadowNode); - calculateShadowViewMutationsV2( - DIFF_BREADCRUMB( - "Stage 1: Recurse on " + - std::to_string(oldChildPair.shadowView.tag)), - *(newGrandChildPairs.size() ? &downwardMutations - : &destructiveDownwardMutations), - oldChildPair.shadowView, - std::move(oldGrandChildPairs), - std::move(newGrandChildPairs)); - } - } - - size_t lastIndexAfterFirstStage = index; - - if (index == newChildPairs.size()) { - // We've reached the end of the new children. We can delete+remove the - // rest. - for (; index < oldChildPairs.size(); index++) { - auto const &oldChildPair = oldChildPairs[index]; - - DEBUG_LOGS({ - LOG(ERROR) << "Differ Branch 2: Deleting Tag/Tree: [" - << oldChildPair.shadowView.tag << "]" - << " with parent: [" << parentShadowView.tag << "]"; - }); - - if (!oldChildPair.isConcreteView) { - continue; - } - - deleteMutations.push_back( - ShadowViewMutation::DeleteMutation(oldChildPair.shadowView)); - removeMutations.push_back(ShadowViewMutation::RemoveMutation( - parentShadowView, - oldChildPair.shadowView, - static_cast(oldChildPair.mountIndex))); - - // We also have to call the algorithm recursively to clean up the entire - // subtree starting from the removed view. - calculateShadowViewMutationsV2( - DIFF_BREADCRUMB( - "Trivial delete " + std::to_string(oldChildPair.shadowView.tag)), - destructiveDownwardMutations, - oldChildPair.shadowView, - sliceChildShadowNodeViewPairsV2(*oldChildPair.shadowNode), - {}); - } - } else if (index == oldChildPairs.size()) { - // If we don't have any more existing children we can choose a fast path - // since the rest will all be create+insert. - for (; index < newChildPairs.size(); index++) { - auto const &newChildPair = newChildPairs[index]; - - DEBUG_LOGS({ - LOG(ERROR) << "Differ Branch 3: Creating Tag/Tree: [" - << newChildPair.shadowView.tag << "]" - << " with parent: [" << parentShadowView.tag << "]"; - }); - - if (!newChildPair.isConcreteView) { - continue; - } - - insertMutations.push_back(ShadowViewMutation::InsertMutation( - parentShadowView, - newChildPair.shadowView, - static_cast(newChildPair.mountIndex))); - createMutations.push_back( - ShadowViewMutation::CreateMutation(newChildPair.shadowView)); - - calculateShadowViewMutationsV2( - DIFF_BREADCRUMB( - "Trivial create " + std::to_string(newChildPair.shadowView.tag)), - downwardMutations, - newChildPair.shadowView, - {}, - sliceChildShadowNodeViewPairsV2(*newChildPair.shadowNode)); - } - } else { - // Collect map of tags in the new list - auto newRemainingPairs = TinyMap{}; - auto newInsertedPairs = TinyMap{}; - auto deletionCandidatePairs = - TinyMap{}; - for (; index < newChildPairs.size(); index++) { - auto &newChildPair = newChildPairs[index]; - newRemainingPairs.insert({newChildPair.shadowView.tag, &newChildPair}); - } - - // Walk through both lists at the same time - // We will perform updates, create+insert, remove+delete, remove+insert - // (move) here. - size_t oldIndex = lastIndexAfterFirstStage, - newIndex = lastIndexAfterFirstStage, newSize = newChildPairs.size(), - oldSize = oldChildPairs.size(); - while (newIndex < newSize || oldIndex < oldSize) { - bool haveNewPair = newIndex < newSize; - bool haveOldPair = oldIndex < oldSize; - - // Advance both pointers if pointing to the same element - if (haveNewPair && haveOldPair) { - auto const &oldChildPair = oldChildPairs[oldIndex]; - auto const &newChildPair = newChildPairs[newIndex]; - - Tag newTag = newChildPair.shadowView.tag; - Tag oldTag = oldChildPair.shadowView.tag; - - if (newTag == oldTag) { - DEBUG_LOGS({ - LOG(ERROR) << "Differ Branch 5: Matched Tags at indices: " - << oldIndex << " " << newIndex << ": [" - << oldChildPair.shadowView.tag << "]" - << (oldChildPair.flattened ? "(flattened)" : "") - << (oldChildPair.isConcreteView ? "(concrete)" : "") - << " [" << newChildPair.shadowView.tag << "]" - << (newChildPair.flattened ? "(flattened)" : "") - << (newChildPair.isConcreteView ? "(concrete)" : "") - << " with parent: [" << parentShadowView.tag << "]"; - }); - - // Check concrete-ness of views - // Create/Delete and Insert/Remove if necessary - if (oldChildPair.isConcreteView != newChildPair.isConcreteView) { - if (newChildPair.isConcreteView) { - insertMutations.push_back(ShadowViewMutation::InsertMutation( - parentShadowView, - newChildPair.shadowView, - static_cast(newChildPair.mountIndex))); - createMutations.push_back( - ShadowViewMutation::CreateMutation(newChildPair.shadowView)); - } else { - removeMutations.push_back(ShadowViewMutation::RemoveMutation( - parentShadowView, - oldChildPair.shadowView, - static_cast(oldChildPair.mountIndex))); - deleteMutations.push_back( - ShadowViewMutation::DeleteMutation(oldChildPair.shadowView)); - } - } else if ( - oldChildPair.isConcreteView && newChildPair.isConcreteView) { - // Even if node's children are flattened, it might still be a - // concrete view. The case where they're different is handled above. - if (oldChildPair.shadowView != newChildPair.shadowView) { - updateMutations.push_back(ShadowViewMutation::UpdateMutation( - oldChildPair.shadowView, newChildPair.shadowView)); - } - - // Remove from newRemainingPairs - auto newRemainingPairIt = newRemainingPairs.find(oldTag); - if (newRemainingPairIt != newRemainingPairs.end()) { - newRemainingPairs.erase(newRemainingPairIt); - } - } - - // Are we flattening or unflattening either one? If node was flattened - // in both trees, there's no change, just continue. - if (oldChildPair.flattened && newChildPair.flattened) { - newIndex++; - oldIndex++; - continue; - } - // We are either flattening or unflattening this node. - if (oldChildPair.flattened != newChildPair.flattened) { - DEBUG_LOGS({ - LOG(ERROR) << "Differ: flattening or unflattening at branch 6: [" - << oldChildPair.shadowView.tag << "] [" - << newChildPair.shadowView.tag << "] " - << oldChildPair.flattened << " " - << newChildPair.flattened << " with parent: [" - << parentShadowView.tag << "]"; - }); - - // Flattening - if (!oldChildPair.flattened) { - // Flatten old tree into new list - // At the end of this loop we still want to know which of these - // children are visited, so we reuse the `newRemainingPairs` map. - calculateShadowViewMutationsFlattener( - DIFF_BREADCRUMB( - "Flatten tree " + std::to_string(parentShadowView.tag) + - " into list " + - std::to_string(oldChildPair.shadowView.tag)), - ReparentMode::Flatten, - mutationInstructionContainer, - parentShadowView, - newRemainingPairs, - oldChildPair); - } - // Unflattening - else { - // Construct unvisited nodes map - auto unvisitedOldChildPairs = - TinyMap{}; - // We don't know where all the children of oldChildPair are within - // oldChildPairs, but we know that they're in the same relative - // order. The reason for this is because of flattening + zIndex: - // the children could be listed before the parent, interwoven with - // children from other nodes, etc. - auto oldFlattenedNodes = sliceChildShadowNodeViewPairsV2( - *oldChildPair.shadowNode, true); - for (size_t i = 0, j = 0; - i < oldChildPairs.size() && j < oldFlattenedNodes.size(); - i++) { - auto &oldChild = oldChildPairs[i]; - if (oldChild.shadowView.tag == - oldFlattenedNodes[j].shadowView.tag) { - unvisitedOldChildPairs.insert( - {oldChild.shadowView.tag, &oldChild}); - j++; - } - } - - // Unflatten old list into new tree - calculateShadowViewMutationsFlattener( - DIFF_BREADCRUMB( - "Unflatten old list " + - std::to_string(parentShadowView.tag) + " into new tree " + - std::to_string(newChildPair.shadowView.tag)), - ReparentMode::Unflatten, - mutationInstructionContainer, - parentShadowView, - unvisitedOldChildPairs, - newChildPair); - - // If old nodes were not visited, we know that we can delete them - // now. They will be removed from the hierarchy by the outermost - // loop of this function. - for (auto &oldFlattenedNode : oldFlattenedNodes) { - auto unvisitedOldChildPairIt = unvisitedOldChildPairs.find( - oldFlattenedNode.shadowView.tag); - if (unvisitedOldChildPairIt == unvisitedOldChildPairs.end()) { - // Node was visited - make sure to remove it from - // "newRemainingPairs" map - auto newRemainingIt = - newRemainingPairs.find(oldFlattenedNode.shadowView.tag); - if (newRemainingIt != newRemainingPairs.end()) { - newRemainingPairs.erase(newRemainingIt); - } - } - } - } - - newIndex++; - oldIndex++; - continue; - } - - // Update subtrees if View is not flattened, and if node addresses are - // not equal - if (oldChildPair.shadowNode != newChildPair.shadowNode) { - auto oldGrandChildPairs = - sliceChildShadowNodeViewPairsV2(*oldChildPair.shadowNode); - auto newGrandChildPairs = - sliceChildShadowNodeViewPairsV2(*newChildPair.shadowNode); - calculateShadowViewMutationsV2( - DIFF_BREADCRUMB( - "Non-trivial update " + - std::to_string(oldChildPair.shadowView.tag)), - *(newGrandChildPairs.size() ? &downwardMutations - : &destructiveDownwardMutations), - oldChildPair.shadowView, - std::move(oldGrandChildPairs), - std::move(newGrandChildPairs)); - } - - newIndex++; - oldIndex++; - continue; - } - } - - // We have an old pair, but we either don't have any remaining new pairs - // or we have one but it's not matched up with the old pair - if (haveOldPair) { - auto const &oldChildPair = oldChildPairs[oldIndex]; - - Tag oldTag = oldChildPair.shadowView.tag; - - // Was oldTag already inserted? This indicates a reordering, not just - // a move. The new node has already been inserted, we just need to - // remove the node from its old position now, and update the node's - // subtree. - auto const insertedIt = newInsertedPairs.find(oldTag); - if (insertedIt != newInsertedPairs.end()) { - auto const &newChildPair = *insertedIt->second; - - // The node has been reordered and we are also flattening or - // unflattening - if (oldChildPair.flattened != newChildPair.flattened) { - DEBUG_LOGS({ - LOG(ERROR) - << "Differ: branch 7: Flattening or unflattening already-inserted node upon remove (move/reorder operation)." - << oldChildPair.shadowView.tag << " " - << oldChildPair.flattened << " // " - << newChildPair.shadowView.tag << " " - << newChildPair.flattened; - }); - - // Unflattening. - // The node in question was already inserted and we are - // *unflattening* it, so we just need to update the subtree nodes - // and remove them from the view hierarchy. Any of the unvisited - // nodes in the old tree will be deleted. - // TODO: can we consolidate this code? It's identical to the first - // block above. - if (!oldChildPair.flattened) { - // Flatten old tree into new list - // At the end of this loop we still want to know which of these - // children are visited, so we reuse the `newRemainingPairs` map. - calculateShadowViewMutationsFlattener( - DIFF_BREADCRUMB( - "Flatten2 " + std::to_string(parentShadowView.tag)), - ReparentMode::Flatten, - mutationInstructionContainer, - parentShadowView, - newRemainingPairs, - oldChildPair); - } - // Unflattening - else { - // Construct unvisited nodes map - auto unvisitedOldChildPairs = - TinyMap{}; - // We don't know where all the children of oldChildPair are within - // oldChildPairs, but we know that they're in the same relative - // order. The reason for this is because of flattening + zIndex: - // the children could be listed before the parent, interwoven with - // children from other nodes, etc. - auto oldFlattenedNodes = sliceChildShadowNodeViewPairsV2( - *oldChildPair.shadowNode, true); - for (size_t i = 0, j = 0; - i < oldChildPairs.size() && j < oldFlattenedNodes.size(); - i++) { - auto &oldChild = oldChildPairs[i]; - if (oldChild.shadowView.tag == - oldFlattenedNodes[j].shadowView.tag) { - unvisitedOldChildPairs.insert( - {oldChild.shadowView.tag, &oldChild}); - j++; - } - } - - // Unflatten old list into new tree - calculateShadowViewMutationsFlattener( - DIFF_BREADCRUMB( - "Unflatten2 " + std::to_string(parentShadowView.tag)), - ReparentMode::Unflatten, - mutationInstructionContainer, - parentShadowView, - unvisitedOldChildPairs, - newChildPair); - - // If old nodes were not visited, we know that we can delete them - // now. They will be removed from the hierarchy by the outermost - // loop of this function. TODO: delete recursively? create - // recursively? - for (auto &oldFlattenedNode : oldFlattenedNodes) { - auto unvisitedOldChildPairIt = unvisitedOldChildPairs.find( - oldFlattenedNode.shadowView.tag); - if (unvisitedOldChildPairIt == unvisitedOldChildPairs.end()) { - // Node was visited - make sure to remove it from - // "newRemainingPairs" map - auto newRemainingIt = - newRemainingPairs.find(oldFlattenedNode.shadowView.tag); - if (newRemainingIt != newRemainingPairs.end()) { - newRemainingPairs.erase(newRemainingIt); - } - } - } - } - } - - // Check concrete-ness of views - // Create/Delete and Insert/Remove if necessary - // TODO: document: Insert should already be handled by outermost loop, - // but not Remove - if (oldChildPair.isConcreteView != newChildPair.isConcreteView) { - if (newChildPair.isConcreteView) { - createMutations.push_back( - ShadowViewMutation::CreateMutation(newChildPair.shadowView)); - } else { - removeMutations.push_back(ShadowViewMutation::RemoveMutation( - parentShadowView, - oldChildPair.shadowView, - static_cast(oldChildPair.mountIndex))); - deleteMutations.push_back( - ShadowViewMutation::DeleteMutation(oldChildPair.shadowView)); - } - } - - // old and new child pairs are both either flattened or unflattened at - // this point. If they're not views, we don't need to update subtrees. - if (oldChildPair.isConcreteView && newChildPair.isConcreteView) { - // TODO: do we always want to remove here? There are cases where we - // might be able to remove this to prevent unnecessary - // removes/inserts in cases of (un)flattening + reorders? - removeMutations.push_back(ShadowViewMutation::RemoveMutation( - parentShadowView, - oldChildPair.shadowView, - static_cast(oldChildPair.mountIndex))); - - if (oldChildPair.shadowView != newChildPair.shadowView) { - updateMutations.push_back(ShadowViewMutation::UpdateMutation( - oldChildPair.shadowView, newChildPair.shadowView)); - } - } - - if (!oldChildPair.flattened && !newChildPair.flattened && - oldChildPair.shadowNode != newChildPair.shadowNode) { - // Update subtrees - auto oldGrandChildPairs = - sliceChildShadowNodeViewPairsV2(*oldChildPair.shadowNode); - auto newGrandChildPairs = - sliceChildShadowNodeViewPairsV2(*newChildPair.shadowNode); - calculateShadowViewMutationsV2( - DIFF_BREADCRUMB( - "Non-trivial update3 " + - std::to_string(oldChildPair.shadowView.tag)), - *(newGrandChildPairs.size() ? &downwardMutations - : &destructiveDownwardMutations), - oldChildPair.shadowView, - std::move(oldGrandChildPairs), - std::move(newGrandChildPairs)); - } - - newInsertedPairs.erase(insertedIt); - oldIndex++; - continue; - } - - // Should we generate a delete+remove instruction for the old node? - // If there's an old node and it's not found in the "new" list, we - // generate remove+delete for this node and its subtree. - auto const newIt = newRemainingPairs.find(oldTag); - if (newIt == newRemainingPairs.end()) { - DEBUG_LOGS({ - LOG(ERROR) - << "Differ Branch 9: Removing tag that was not reinserted: " - << oldIndex << ": [" << oldChildPair.shadowView.tag << "]" - << (oldChildPair.flattened ? " (flattened)" : "") - << (oldChildPair.isConcreteView ? " (concrete)" : "") - << " with parent: [" << parentShadowView.tag << "] " - << "node is in other tree? " - << (oldChildPair.inOtherTree ? "yes" : "no"); - }); - - if (oldChildPair.isConcreteView) { - removeMutations.push_back(ShadowViewMutation::RemoveMutation( - parentShadowView, - oldChildPair.shadowView, - static_cast(oldChildPair.mountIndex))); - - deletionCandidatePairs.insert( - {oldChildPair.shadowView.tag, &oldChildPair}); - } - - oldIndex++; - continue; - } - } - - // At this point, oldTag is -1 or is in the new list, and hasn't been - // inserted or matched yet. We're not sure yet if the new node is in the - // old list - generate an insert instruction for the new node. - auto &newChildPair = newChildPairs[newIndex]; - DEBUG_LOGS({ - LOG(ERROR) - << "Differ Branch 10: Inserting tag/tree that was not (yet?) removed from hierarchy: " - << newIndex << "/" << newSize << ": [" - << newChildPair.shadowView.tag << "]" - << (newChildPair.flattened ? " (flattened)" : "") - << (newChildPair.isConcreteView ? " (concrete)" : "") - << " with parent: [" << parentShadowView.tag << "]"; - }); - if (newChildPair.isConcreteView) { - insertMutations.push_back(ShadowViewMutation::InsertMutation( - parentShadowView, - newChildPair.shadowView, - static_cast(newChildPair.mountIndex))); - } - - // `inOtherTree` is only set to true during flattening/unflattening of - // parent. If the parent isn't (un)flattened, this will always be `false`, - // even if the node is in the other (old) tree. In this case, we expect - // the node to be removed from `newInsertedPairs` when we later encounter - // it in this loop. - if (!newChildPair.inOtherTree) { - newInsertedPairs.insert({newChildPair.shadowView.tag, &newChildPair}); - } - - newIndex++; - } - - // Penultimate step: generate Delete instructions for entirely deleted - // subtrees/nodes. We do this here because we need to traverse the entire - // list to make sure that a node was not reparented into an unflattened node - // that occurs *after* it in the hierarchy, due to zIndex ordering. - for (auto it = deletionCandidatePairs.begin(); - it != deletionCandidatePairs.end(); - it++) { - if (it->first == 0) { - continue; - } - - auto const &oldChildPair = *it->second; - - DEBUG_LOGS({ - LOG(ERROR) - << "Differ Branch 11: Deleting tag/tree that was not in new hierarchy: " - << "[" << oldChildPair.shadowView.tag << "]" - << (oldChildPair.flattened ? "(flattened)" : "") - << (oldChildPair.isConcreteView ? "(concrete)" : "") - << (oldChildPair.inOtherTree ? "(in other tree)" : "") - << " with parent: [" << parentShadowView.tag << "]"; - }); - - // This can happen when the parent is unflattened - if (!oldChildPair.inOtherTree) { - deleteMutations.push_back( - ShadowViewMutation::DeleteMutation(oldChildPair.shadowView)); - - // We also have to call the algorithm recursively to clean up the - // entire subtree starting from the removed view. - calculateShadowViewMutationsV2( - DIFF_BREADCRUMB( - "Non-trivial delete " + - std::to_string(oldChildPair.shadowView.tag)), - destructiveDownwardMutations, - oldChildPair.shadowView, - sliceChildShadowNodeViewPairsV2(*oldChildPair.shadowNode), - {}); - } - } - - // Final step: generate Create instructions for entirely new subtrees/nodes - // that are not the result of flattening or unflattening. - for (auto it = newInsertedPairs.begin(); it != newInsertedPairs.end(); - it++) { - // Erased elements of a TinyMap will have a Tag/key of 0 - skip those - // These *should* be removed by the map; there are currently no KNOWN - // cases where TinyMap will do the wrong thing, but there are not yet - // any unit tests explicitly for TinyMap, so this is safer for now. - if (it->first == 0) { - continue; - } - - auto const &newChildPair = *it->second; - - DEBUG_LOGS({ - LOG(ERROR) - << "Differ Branch 12: Inserting tag/tree that was not in old hierarchy: " - << "[" << newChildPair.shadowView.tag << "]" - << (newChildPair.flattened ? "(flattened)" : "") - << (newChildPair.isConcreteView ? "(concrete)" : "") - << (newChildPair.inOtherTree ? "(in other tree)" : "") - << " with parent: [" << parentShadowView.tag << "]"; - }); - - if (!newChildPair.isConcreteView) { - continue; - } - if (newChildPair.inOtherTree) { - continue; - } - - createMutations.push_back( - ShadowViewMutation::CreateMutation(newChildPair.shadowView)); - - calculateShadowViewMutationsV2( - DIFF_BREADCRUMB( - "Non-trivial create " + - std::to_string(newChildPair.shadowView.tag)), - downwardMutations, - newChildPair.shadowView, - {}, - sliceChildShadowNodeViewPairsV2(*newChildPair.shadowNode)); - } - } - - // All mutations in an optimal order: - std::move( - destructiveDownwardMutations.begin(), - destructiveDownwardMutations.end(), - std::back_inserter(mutations)); - std::move( - updateMutations.begin(), - updateMutations.end(), - std::back_inserter(mutations)); - std::move( - removeMutations.rbegin(), - removeMutations.rend(), - std::back_inserter(mutations)); - std::move( - deleteMutations.begin(), - deleteMutations.end(), - std::back_inserter(mutations)); - std::move( - createMutations.begin(), - createMutations.end(), - std::back_inserter(mutations)); - std::move( - downwardMutations.begin(), - downwardMutations.end(), - std::back_inserter(mutations)); - std::move( - insertMutations.begin(), - insertMutations.end(), - std::back_inserter(mutations)); -} - -ShadowViewMutation::List calculateShadowViewMutations( - ShadowNode const &oldRootShadowNode, - ShadowNode const &newRootShadowNode) { - SystraceSection s("calculateShadowViewMutations"); - - // Root shadow nodes must be belong the same family. - react_native_assert( - ShadowNode::sameFamily(oldRootShadowNode, newRootShadowNode)); - - auto mutations = ShadowViewMutation::List{}; - mutations.reserve(256); - - auto oldRootShadowView = ShadowView(oldRootShadowNode); - auto newRootShadowView = ShadowView(newRootShadowNode); - - if (oldRootShadowView != newRootShadowView) { - mutations.push_back(ShadowViewMutation::UpdateMutation( - oldRootShadowView, newRootShadowView)); - } - - calculateShadowViewMutationsV2( - CREATE_DIFF_BREADCRUMB(oldRootShadowView.tag), - mutations, - ShadowView(oldRootShadowNode), - sliceChildShadowNodeViewPairsV2(oldRootShadowNode), - sliceChildShadowNodeViewPairsV2(newRootShadowNode)); - - return mutations; -} - -} // namespace DifferOld -} // namespace react -} // namespace facebook diff --git a/ReactCommon/react/renderer/mounting/DifferentiatorFlatteningClassic.h b/ReactCommon/react/renderer/mounting/DifferentiatorFlatteningClassic.h deleted file mode 100644 index e344bd211e..0000000000 --- a/ReactCommon/react/renderer/mounting/DifferentiatorFlatteningClassic.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#pragma once - -// This file exists as an experimental baseline against which -// we can compare changes in Differentiator. -// Once changes in Differentiator have been verified safe, -// this file will be deleted. - -#include -#include -#include - -namespace facebook { -namespace react { -namespace DifferOld { - -enum class ReparentMode { Flatten, Unflatten }; - -/* - * Calculates a list of view mutations which describes how the old - * `ShadowTree` can be transformed to the new one. - * The list of mutations might be and might not be optimal. - */ -ShadowViewMutationList calculateShadowViewMutations( - ShadowNode const &oldRootShadowNode, - ShadowNode const &newRootShadowNode); - -/** - * Generates a list of `ShadowViewNodePair`s that represents a layer of a - * flattened view hierarchy. The V2 version preserves nodes even if they do - * not form views and their children are flattened. - */ -ShadowViewNodePairLegacy::OwningList sliceChildShadowNodeViewPairsV2( - ShadowNode const &shadowNode, - bool allowFlattened = false); - -} // namespace DifferOld -} // namespace react -} // namespace facebook diff --git a/ReactCommon/react/renderer/mounting/MountingCoordinator.cpp b/ReactCommon/react/renderer/mounting/MountingCoordinator.cpp index ad66e2296d..98001cfa1c 100644 --- a/ReactCommon/react/renderer/mounting/MountingCoordinator.cpp +++ b/ReactCommon/react/renderer/mounting/MountingCoordinator.cpp @@ -90,9 +90,7 @@ better::optional MountingCoordinator::pullTransaction() telemetry.willDiff(); auto mutations = calculateShadowViewMutations( - *baseRevision_.rootShadowNode, - *lastRevision_->rootShadowNode, - enableNewDiffer_); + *baseRevision_.rootShadowNode, *lastRevision_->rootShadowNode); telemetry.didDiff(); @@ -188,9 +186,5 @@ void MountingCoordinator::setMountingOverrideDelegate( mountingOverrideDelegate_ = delegate; } -void MountingCoordinator::setEnableNewDiffer(bool enabled) const { - enableNewDiffer_ = enabled; -} - } // namespace react } // namespace facebook diff --git a/ReactCommon/react/renderer/mounting/MountingCoordinator.h b/ReactCommon/react/renderer/mounting/MountingCoordinator.h index 8d434f43ad..00c12ba068 100644 --- a/ReactCommon/react/renderer/mounting/MountingCoordinator.h +++ b/ReactCommon/react/renderer/mounting/MountingCoordinator.h @@ -71,8 +71,6 @@ class MountingCoordinator final { TelemetryController const &getTelemetryController() const; - void setEnableNewDiffer(bool enabled) const; - /* * Methods from this section are meant to be used by * `MountingOverrideDelegate` only. @@ -114,8 +112,6 @@ class MountingCoordinator final { TelemetryController telemetryController_; - mutable bool enableNewDiffer_{false}; - #ifdef RN_SHADOW_TREE_INTROSPECTION mutable StubViewTree stubViewTree_; // Protected by `mutex_`. #endif diff --git a/ReactCommon/react/renderer/mounting/ShadowTree.cpp b/ReactCommon/react/renderer/mounting/ShadowTree.cpp index 5d074d7a97..2ed6f90cd2 100644 --- a/ReactCommon/react/renderer/mounting/ShadowTree.cpp +++ b/ReactCommon/react/renderer/mounting/ShadowTree.cpp @@ -223,8 +223,7 @@ ShadowTree::ShadowTree( SurfaceId surfaceId, LayoutConstraints const &layoutConstraints, LayoutContext const &layoutContext, - ShadowTreeDelegate const &delegate, - bool enableNewDiffer) + ShadowTreeDelegate const &delegate) : surfaceId_(surfaceId), delegate_(delegate) { const auto noopEventEmitter = std::make_shared( nullptr, -1, std::shared_ptr()); @@ -253,7 +252,6 @@ ShadowTree::ShadowTree( mountingCoordinator_ = std::make_shared(currentRevision_); - mountingCoordinator_->setEnableNewDiffer(enableNewDiffer); } ShadowTree::~ShadowTree() { diff --git a/ReactCommon/react/renderer/mounting/ShadowTree.h b/ReactCommon/react/renderer/mounting/ShadowTree.h index dcfc584f64..2a8f1d1fad 100644 --- a/ReactCommon/react/renderer/mounting/ShadowTree.h +++ b/ReactCommon/react/renderer/mounting/ShadowTree.h @@ -70,8 +70,7 @@ class ShadowTree final { SurfaceId surfaceId, LayoutConstraints const &layoutConstraints, LayoutContext const &layoutContext, - ShadowTreeDelegate const &delegate, - bool enableNewDiffer); + ShadowTreeDelegate const &delegate); ~ShadowTree(); diff --git a/ReactCommon/react/renderer/mounting/stubs.cpp b/ReactCommon/react/renderer/mounting/stubs.cpp index 02fb98597c..c5f76beb20 100644 --- a/ReactCommon/react/renderer/mounting/stubs.cpp +++ b/ReactCommon/react/renderer/mounting/stubs.cpp @@ -89,7 +89,7 @@ StubViewTree buildStubViewTreeUsingDifferentiator( ShadowNode::emptySharedShadowNodeSharedList()}); auto mutations = - calculateShadowViewMutations(*emptyRootShadowNode, rootShadowNode, true); + calculateShadowViewMutations(*emptyRootShadowNode, rootShadowNode); auto stubViewTree = StubViewTree(ShadowView(*emptyRootShadowNode)); stubViewTree.mutate(mutations); diff --git a/ReactCommon/react/renderer/mounting/tests/MountingTest.cpp b/ReactCommon/react/renderer/mounting/tests/MountingTest.cpp index 6c407f15f4..bd90f794d8 100644 --- a/ReactCommon/react/renderer/mounting/tests/MountingTest.cpp +++ b/ReactCommon/react/renderer/mounting/tests/MountingTest.cpp @@ -242,8 +242,7 @@ TEST(MountingTest, testReorderingInstructionGeneration) { }*/ // Calculating mutations. - auto mutations1 = - calculateShadowViewMutations(*rootNodeV1, *rootNodeV2, true); + auto mutations1 = calculateShadowViewMutations(*rootNodeV1, *rootNodeV2); // The order and exact mutation instructions here may change at any time. // This test just ensures that any changes are intentional. @@ -259,8 +258,7 @@ TEST(MountingTest, testReorderingInstructionGeneration) { EXPECT_TRUE(mutations1[1].index == 0); // Calculating mutations. - auto mutations2 = - calculateShadowViewMutations(*rootNodeV2, *rootNodeV3, true); + auto mutations2 = calculateShadowViewMutations(*rootNodeV2, *rootNodeV3); // The order and exact mutation instructions here may change at any time. // This test just ensures that any changes are intentional. @@ -276,8 +274,7 @@ TEST(MountingTest, testReorderingInstructionGeneration) { EXPECT_TRUE(mutations2[1].oldChildShadowView.tag == 100); // Calculating mutations. - auto mutations3 = - calculateShadowViewMutations(*rootNodeV3, *rootNodeV4, true); + auto mutations3 = calculateShadowViewMutations(*rootNodeV3, *rootNodeV4); LOG(ERROR) << "Num mutations IN OLD TEST mutations3: " << mutations3.size(); // The order and exact mutation instructions here may change at any time. @@ -299,8 +296,7 @@ TEST(MountingTest, testReorderingInstructionGeneration) { EXPECT_TRUE(mutations3[3].index == 2); // Calculating mutations. - auto mutations4 = - calculateShadowViewMutations(*rootNodeV4, *rootNodeV5, true); + auto mutations4 = calculateShadowViewMutations(*rootNodeV4, *rootNodeV5); // The order and exact mutation instructions here may change at any time. // This test just ensures that any changes are intentional. @@ -325,8 +321,7 @@ TEST(MountingTest, testReorderingInstructionGeneration) { EXPECT_TRUE(mutations4[5].newChildShadowView.tag == 102); EXPECT_TRUE(mutations4[5].index == 3); - auto mutations5 = - calculateShadowViewMutations(*rootNodeV5, *rootNodeV6, true); + auto mutations5 = calculateShadowViewMutations(*rootNodeV5, *rootNodeV6); // The order and exact mutation instructions here may change at any time. // This test just ensures that any changes are intentional. @@ -345,8 +340,7 @@ TEST(MountingTest, testReorderingInstructionGeneration) { EXPECT_TRUE(mutations5[3].newChildShadowView.tag == 105); EXPECT_TRUE(mutations5[3].index == 3); - auto mutations6 = - calculateShadowViewMutations(*rootNodeV6, *rootNodeV7, true); + auto mutations6 = calculateShadowViewMutations(*rootNodeV6, *rootNodeV7); // The order and exact mutation instructions here may change at any time. // This test just ensures that any changes are intentional. @@ -600,8 +594,7 @@ TEST(MountingTest, testViewReparentingInstructionGeneration) { rootNodeV5->sealRecursive(); // Calculating mutations. - auto mutations1 = - calculateShadowViewMutations(*rootNodeV1, *rootNodeV2, true); + auto mutations1 = calculateShadowViewMutations(*rootNodeV1, *rootNodeV2); EXPECT_EQ(mutations1.size(), 5); EXPECT_EQ(mutations1[0].type, ShadowViewMutation::Update); @@ -615,8 +608,7 @@ TEST(MountingTest, testViewReparentingInstructionGeneration) { EXPECT_EQ(mutations1[4].type, ShadowViewMutation::Insert); EXPECT_EQ(mutations1[4].newChildShadowView.tag, 1000); - auto mutations2 = - calculateShadowViewMutations(*rootNodeV2, *rootNodeV3, true); + auto mutations2 = calculateShadowViewMutations(*rootNodeV2, *rootNodeV3); EXPECT_EQ(mutations2.size(), 5); EXPECT_EQ(mutations2[0].type, ShadowViewMutation::Update); @@ -632,8 +624,7 @@ TEST(MountingTest, testViewReparentingInstructionGeneration) { EXPECT_EQ(mutations2[4].type, ShadowViewMutation::Insert); EXPECT_EQ(mutations2[4].newChildShadowView.tag, 1000); - auto mutations3 = - calculateShadowViewMutations(*rootNodeV3, *rootNodeV4, true); + auto mutations3 = calculateShadowViewMutations(*rootNodeV3, *rootNodeV4); // between these two trees, lots of new nodes are created and inserted - this // is all correct, and this is the minimal amount of mutations @@ -670,8 +661,7 @@ TEST(MountingTest, testViewReparentingInstructionGeneration) { EXPECT_EQ(mutations3[14].type, ShadowViewMutation::Insert); EXPECT_EQ(mutations3[14].newChildShadowView.tag, 1000); - auto mutations4 = - calculateShadowViewMutations(*rootNodeV4, *rootNodeV5, true); + auto mutations4 = calculateShadowViewMutations(*rootNodeV4, *rootNodeV5); EXPECT_EQ(mutations4.size(), 9); EXPECT_EQ(mutations4[0].type, ShadowViewMutation::Update); diff --git a/ReactCommon/react/renderer/mounting/tests/ShadowTreeLifeCycleTest.cpp b/ReactCommon/react/renderer/mounting/tests/ShadowTreeLifeCycleTest.cpp index 813dadb1e1..f0ed62cfa2 100644 --- a/ReactCommon/react/renderer/mounting/tests/ShadowTreeLifeCycleTest.cpp +++ b/ReactCommon/react/renderer/mounting/tests/ShadowTreeLifeCycleTest.cpp @@ -79,7 +79,7 @@ static void testShadowNodeTreeLifeCycle( // Building an initial view hierarchy. auto viewTree = buildStubViewTreeWithoutUsingDifferentiator(*emptyRootNode); viewTree.mutate( - calculateShadowViewMutations(*emptyRootNode, *currentRootNode, true)); + calculateShadowViewMutations(*emptyRootNode, *currentRootNode)); for (int j = 0; j < stages; j++) { auto nextRootNode = currentRootNode; @@ -106,7 +106,7 @@ static void testShadowNodeTreeLifeCycle( // Calculating mutations. auto mutations = - calculateShadowViewMutations(*currentRootNode, *nextRootNode, true); + calculateShadowViewMutations(*currentRootNode, *nextRootNode); // Make sure that in a single frame, a DELETE for a // view is not followed by a CREATE for the same view. @@ -226,7 +226,7 @@ static void testShadowNodeTreeLifeCycleExtensiveFlatteningUnflattening( // Building an initial view hierarchy. auto viewTree = buildStubViewTreeWithoutUsingDifferentiator(*emptyRootNode); viewTree.mutate( - calculateShadowViewMutations(*emptyRootNode, *currentRootNode, true)); + calculateShadowViewMutations(*emptyRootNode, *currentRootNode)); for (int j = 0; j < stages; j++) { auto nextRootNode = currentRootNode; @@ -254,7 +254,7 @@ static void testShadowNodeTreeLifeCycleExtensiveFlatteningUnflattening( // Calculating mutations. auto mutations = - calculateShadowViewMutations(*currentRootNode, *nextRootNode, true); + calculateShadowViewMutations(*currentRootNode, *nextRootNode); // Make sure that in a single frame, a DELETE for a // view is not followed by a CREATE for the same view. diff --git a/ReactCommon/react/renderer/mounting/tests/StackingContextTest.cpp b/ReactCommon/react/renderer/mounting/tests/StackingContextTest.cpp index b4b5b204c8..521d3135d1 100644 --- a/ReactCommon/react/renderer/mounting/tests/StackingContextTest.cpp +++ b/ReactCommon/react/renderer/mounting/tests/StackingContextTest.cpp @@ -171,8 +171,8 @@ class StackingContextTest : public ::testing::Test { callback(buildStubViewTreeUsingDifferentiator(*rootShadowNode_)); callback(buildStubViewTreeWithoutUsingDifferentiator(*rootShadowNode_)); - auto mutations = calculateShadowViewMutations( - *currentRootShadowNode_, *rootShadowNode_, true); + auto mutations = + calculateShadowViewMutations(*currentRootShadowNode_, *rootShadowNode_); currentRootShadowNode_ = rootShadowNode_; currentStubViewTree_.mutate(mutations); callback(currentStubViewTree_); diff --git a/ReactCommon/react/renderer/mounting/tests/StateReconciliationTest.cpp b/ReactCommon/react/renderer/mounting/tests/StateReconciliationTest.cpp index d595e522ec..c8f80e5b0f 100644 --- a/ReactCommon/react/renderer/mounting/tests/StateReconciliationTest.cpp +++ b/ReactCommon/react/renderer/mounting/tests/StateReconciliationTest.cpp @@ -98,11 +98,7 @@ TEST(StateReconciliationTest, testStateReconciliation) { auto state1 = shadowNodeAB->getState(); auto shadowTreeDelegate = DummyShadowTreeDelegate{}; ShadowTree shadowTree{ - SurfaceId{11}, - LayoutConstraints{}, - LayoutContext{}, - shadowTreeDelegate, - true}; + SurfaceId{11}, LayoutConstraints{}, LayoutContext{}, shadowTreeDelegate}; shadowTree.commit( [&](RootShadowNode const &oldRootShadowNode) { diff --git a/ReactCommon/react/renderer/scheduler/Scheduler.cpp b/ReactCommon/react/renderer/scheduler/Scheduler.cpp index 735295b972..2ea92bb199 100644 --- a/ReactCommon/react/renderer/scheduler/Scheduler.cpp +++ b/ReactCommon/react/renderer/scheduler/Scheduler.cpp @@ -143,14 +143,11 @@ Scheduler::Scheduler( #ifdef ANDROID removeOutstandingSurfacesOnDestruction_ = reactNativeConfig_->getBool( "react_fabric:remove_outstanding_surfaces_on_destruction_android"); - enableNewDiffer_ = reactNativeConfig_->getBool( - "react_fabric:enable_new_differ_h1_2021_android"); Constants::setPropsForwardingEnabled(reactNativeConfig_->getBool( "react_fabric:enable_props_forwarding_android")); #else removeOutstandingSurfacesOnDestruction_ = reactNativeConfig_->getBool( "react_fabric:remove_outstanding_surfaces_on_destruction_ios"); - enableNewDiffer_ = true; #endif } @@ -213,7 +210,6 @@ Scheduler::~Scheduler() { void Scheduler::registerSurface( SurfaceHandler const &surfaceHandler) const noexcept { surfaceHandler.setUIManager(uiManager_.get()); - surfaceHandler.setEnableNewDiffer(enableNewDiffer_); } void Scheduler::unregisterSurface( diff --git a/ReactCommon/react/renderer/scheduler/Scheduler.h b/ReactCommon/react/renderer/scheduler/Scheduler.h index 66a437dfce..03c8f65d2e 100644 --- a/ReactCommon/react/renderer/scheduler/Scheduler.h +++ b/ReactCommon/react/renderer/scheduler/Scheduler.h @@ -121,7 +121,6 @@ class Scheduler final : public UIManagerDelegate { * Temporary flags. */ bool removeOutstandingSurfacesOnDestruction_{false}; - bool enableNewDiffer_{false}; }; } // namespace react diff --git a/ReactCommon/react/renderer/scheduler/SurfaceHandler.cpp b/ReactCommon/react/renderer/scheduler/SurfaceHandler.cpp index cd88ce86b6..6cb7fb2545 100644 --- a/ReactCommon/react/renderer/scheduler/SurfaceHandler.cpp +++ b/ReactCommon/react/renderer/scheduler/SurfaceHandler.cpp @@ -71,8 +71,7 @@ void SurfaceHandler::start() const noexcept { parameters.surfaceId, parameters.layoutConstraints, parameters.layoutContext, - *link_.uiManager, - enableNewDiffer_); + *link_.uiManager); link_.shadowTree = shadowTree.get(); @@ -139,11 +138,6 @@ DisplayMode SurfaceHandler::getDisplayMode() const noexcept { return parameters_.displayMode; } -#pragma mark - Feature Flags -void SurfaceHandler::setEnableNewDiffer(bool enabled) const noexcept { - enableNewDiffer_ = enabled; -} - #pragma mark - Accessors SurfaceId SurfaceHandler::getSurfaceId() const noexcept { diff --git a/ReactCommon/react/renderer/scheduler/SurfaceHandler.h b/ReactCommon/react/renderer/scheduler/SurfaceHandler.h index 3e8233794c..b564f5ebac 100644 --- a/ReactCommon/react/renderer/scheduler/SurfaceHandler.h +++ b/ReactCommon/react/renderer/scheduler/SurfaceHandler.h @@ -138,9 +138,6 @@ class SurfaceHandler final { LayoutConstraints getLayoutConstraints() const noexcept; LayoutContext getLayoutContext() const noexcept; -#pragma mark - Feature Flags - void setEnableNewDiffer(bool enabled) const noexcept; - private: friend class Scheduler; @@ -198,11 +195,6 @@ class SurfaceHandler final { */ mutable better::shared_mutex parametersMutex_; mutable Parameters parameters_; - - /** - * Feature flags. - */ - mutable bool enableNewDiffer_{false}; }; } // namespace react