Summary:
This introduces a new shadow node trait (`Hidden`) which disables emitting ShadowVides for such nodes and all their descendants.
Changelog: [Internal] Fabric-specific internal change.
Reviewed By: sammy-SC
Differential Revision: D22134220
fbshipit-source-id: 8ea1fc3186019005ad687eacaca0ba4a4d8343dc
Summary:
This diff fixes the position of TextInlineViews when nesting multiple Text.
The root is that we were not taking into consideration LayoutOffset of nested TextViews during the calculation of the nested views.
changelog: [Internal] Internal fix in Fabric
Reviewed By: JoshuaGross
Differential Revision: D21586893
fbshipit-source-id: 55e6ad0cf95222588ffe9185f5e22baea1059448
Summary:
Changelog: [Internal]
Using `empty()` vs `size() == 0` or `size() > 0`.
It is a more semantic way to check whether container is empty or not.
Reviewed By: JoshuaGross
Differential Revision: D21573183
fbshipit-source-id: b83283f687432a037941852114717a0f014e28db
Summary:
The core issue solved in D21389371 was that erased elements of a TinyMap were being iterated over, because TinyMap has somewhat-complicated logic around cleaning out the underlying vector. In some very marginal cases, vectors were not being cleaned and an iterator pointing at erased elements was being returned.
The diff prevents some possible crashes in `begin()` and `find()` while making it much less likely to iterate over erased elements.
We also add a unit test to catch the case fixed in D21389371, in particular.
We also are keeping the code added in D21389371 (for now) since it's a cheap check, and will be a safeguard until we have rigorous testing around TinyMap. To be clear that logic should noop currently, but will prevent crashes in case guarantees around TinyMap change in the future.
Currently there is only one line of code that actually uses the TinyMap iterator, so this should be safe.
Reviewed By: shergin
Differential Revision: D21392762
fbshipit-source-id: 36dc998958c230fad01af93338974f8889cbcf55
Summary:
When we call `.erase` on the TinyMap, it sets the key of the element to 0. When we call `.begin()` later, TinyMap will sometimes, but not always, clean up the underlying Vector. This means that *most* of the time, underlying erased elements will be removed from the Vector; but sometimes erased elements will still be there when iterating over it.
This was causing us to generate extra "Create" mutations.
To fix this, for now we just check for zeroed-out elements when iterating over the vector.
Changelog: [Internal]
Reviewed By: mdvacca
Differential Revision: D21389371
fbshipit-source-id: 1e641050987d40a3f3e31499dcb373cfb28ae6f8
Summary:
The differ was still producing correct, but not minimal, instruction sets in some cases due to an optimization that was buggy.
This affected cases where 2+ nodes were inserted at the beginning of a list. It would trigger the old behavior where all nodes after the first would be removed, deleted, then reinserted.
See the test case (which was failing and now passed) and P128190998 (the 3->4 transition) for samples.
Changelog: [Internal] Fabric differ
Reviewed By: mdvacca
Differential Revision: D20785729
fbshipit-source-id: 2fea6a816753066abb358ed7bb51003140cd5fc4
Summary:
Two things:
1) I reimplement Valentin's idea in D19965405, so that TinyMaps can be iterated over, with a couple of bugfixes (calling front() or back() on an empty vector will crash).
2) I now use TinyMap instead of better::map in the "optimized" diffing algorithm.
3) `erase` now actually removes elements from the vector, but only when more than half of elements have been erased.
4) If you repeatedly erase elements at the beginning of the vector, they will no longer be iterated over. This is a specific optimization for our heaviest TinyMap use-cases.
These amount to some small but hopefully somewhat meaningful perf improvements.
Changelog: [Internal] Fabric perf
Reviewed By: shergin
Differential Revision: D20718719
fbshipit-source-id: 91f4b2e2e0f6387ae484e43d5b0095103087baa6
Summary:
An evolution of D20633188 but more performant.
There are three optimized paths before the slow path.
The first optimized path tries to pair identical nodes from old/new tree, and generate Update mutations, until we hit nodes that are different (indicating either a remove or an insert). This already existed.
The next two optimizations, introduced by Tim in his JS pseudocode, were inspired by ReactJS's diffing algorithm. They work in cases where the rest of the nodes are (1) all removals/deletes or (2) all creates+inserts.
Finally, if those final two optimized paths can't run, it's because there is a mix of delete+remove, create+insert, and "move" operations, mixed at the beginning, middle, and/or end of the list.
This has slightly better average/best-case complexity as the previous implementation.
In particularly pathological cases where all nodes are arbitrarily reordered, or reversed, for instance (ABCDE->EDCBA) the algorithm has the same complexity as the previous algorithm (quadratic).
For now iOS is pinned to the older differ
Changelog: [Internal] Experiment to optimize diffing algorithm in Fabric
Reviewed By: shergin
Differential Revision: D20684094
fbshipit-source-id: d29fba95a0328156c023e1c87804f23770ee1d91
Summary:
The diff introduces a new field in `ShadowNode` which defines in which order ShadowViews created from the node and its siblings will appear ShadowView tree. The feature will be used to overcome some platform limitations (e.g. on Android) on the mounting layer (it will be able to move some nodes of some time to the end (or beginning) of the list) and build features like zIndex ordering in C++ core.
Changelog: [Internal] Fabric-specific internal change.
Reviewed By: mdvacca
Differential Revision: D20396718
fbshipit-source-id: 16aef7c2b5511c874341ab7554e5585b2cdc356f
Summary:
This diff changes how we pass lists of nodes to `calculateShadowViewMutations`: previously we passed that as `const &` and now we pass them as rvalue references because we will need to mute them in the future diffs.
This diff also adds a `static_assert` to ensure that the lists are movable.
Changelog: [Internal] Fabric-specific internal change.
Reviewed By: mdvacca
Differential Revision: D20353754
fbshipit-source-id: 0c3383bff6ded8a49d1ac003fce8919d3906b5bb
Summary: Now, following the previous diff, we remove `LayoutableShadowNode::isLayoutOnly()` and change the view flattening algorithm to rely on two new traits. See the previous diff to learn more about how it works.
Reviewed By: sammy-SC
Differential Revision: D20212252
fbshipit-source-id: 87a07e8bb17b2e66e5703f107dc35ca7a8e49634
Summary:
What's changed:
* `end()` now returns the pointer to the imaginary element after the very last one (which is aligned with STL);
* `erase()` now swaps the removing and the last elements and shrinks the size of an array.
Changelog: [Internal] Fabric-specific internal change.
Reviewed By: sammy-SC
Differential Revision: D19965405
fbshipit-source-id: 92eedf38d55be35a0d9ab6120634b51c8d6e4674
Summary:
The Diffing is one of the hottest pieces of Fabric. Removing dynamic_cast here should improve perf. See the previous diff for more details.
Changelog: [Internal] Fabric-specific internal change.
Reviewed By: sammy-SC
Differential Revision: D20052030
fbshipit-source-id: 27fd9f34f2a1f9d22b9da6b1e3c1a2982045c07a
Summary:
Here is a mutation test for the Diffing algorithm that we use to diff ShadowNode trees and flatten them. As a side-effect, it also "tests" that Concurrent Yoga does not crash and produces decent cloning requests.
The test works this way:
1. We create a random ShadowNode tree;
2. We create a View tree from that that we continue to maintain;
3. We apply random mutation on this;
4. We layout the tree;
5. We generate the mutation instruction comparing a previous tree with a new one;
6. We apply mutations on the first tree;
7. We generate a new tree from scratch;
8. We compare the new tree with the tree updated with mutations and expect equivalence;
9. Repeat a million times.
Changelog: [Internal] Fabric-specific internal change.
Reviewed By: JoshuaGross, mdvacca
Differential Revision: D19357714
fbshipit-source-id: 04765ede87d91180952ae650ff0d505dfac2ed8e
Summary:
`stubViewTreeFromShadowNode` was implemented without using `calculateShadowViewMutations` (aka Diffing algorithm).
The problem is that we use `stubViewTreeFromShadowNode` to test the diffing, so it was not fully correct to use the algorithm to test itself.
Reviewed By: JoshuaGross
Differential Revision: D16342526
fbshipit-source-id: 2674245ed5ec71309fe5d362779a33d8dd31dc7b
Summary: I am about to change the definition of ShadowView a bit, so I think we need to ensure that we don't regress move semantic.
Reviewed By: JoshuaGross, sammy-SC
Differential Revision: D15911453
fbshipit-source-id: ce2cd4cb2375ecb76295948a1e9b5d2e7fb80f38
Summary: This is a temporary backout of D14817454, to verify if this is related T45503571
Reviewed By: JoshuaGross
Differential Revision: D15780018
fbshipit-source-id: 455034ce7b7096101db93a8604b77e1233db1137
Summary: Diffing algorithm uses a small map for every layer of shadow tree; that's a lot of maps. Luckily, it does not need a complex feature-full map (which is not free to allocate and use), it needs a tiny map with a dozen values. Why do we need to pay for what we don't use? This diff introduces a trivial map optimized for constraints that we have here. (See more details in the code.)
Reviewed By: mdvacca
Differential Revision: D15200495
fbshipit-source-id: d859b68b9543253840b403e7430f945a0b76d87b
Summary:
This is a small micro-optimization in Diffing algorithm.
Seems we don't need to store full ShadowView objects in `insertedPairs` map, we can store only pointers to them. That can save memory and CPU cycles because we will not need to store full objects and copy shared pointers (which is somewhat expensive).
Reviewed By: mdvacca
Differential Revision: D15200498
fbshipit-source-id: 2a268c3ee80755555bff3317e10e679be1cf9830
Summary: Diffing is already pretty fast, but using move semantic should make it even faster. ShadowViews have shared pointers, so moving them can save us atomic counter bumps.
Reviewed By: mdvacca
Differential Revision: D15200496
fbshipit-source-id: 6fb0eb79e07cd6ae9b3100713497c634f306bc18
Summary:
This diff changes the way views are inserted by the diffing algorithm.
Previously the diffing algorithm inserted views top-down, now it insert views bottom-up (same order as previous version of RN).
Let say we need to create the following tree:
```
A --> B --> C
|
| --> D
```
Before, the diffing algorithm created the following list of instructions:
```
insert(A, B, 0)
insert(B, C, 0)
insert(B, D, 1)
```
After this diff, the insert instructions are going to be:
```
insert(B, C, 0)
insert(B, D, 1)
insert(A, B, 0)
```
Reviewed By: shergin
Differential Revision: D14817454
fbshipit-source-id: 7aac1a1e1784c53bca2747aee80a5bc8ee788e7a
Summary: Before the fix, the algorithm compares ShadowViews to make a decision should it recursively call itself or not; that didn't work properly because a ShadowView doesn't fully represent the state of the subtree tree (e.g. they don't have information about children nodes). After the fix, we compare pointers to ShadowNodes (by comparing pairs).
Reviewed By: mdvacca
Differential Revision: D14696996
fbshipit-source-id: 560d623b15a272f13b08a11745dec6be39a5dbdd
Summary:
ShadowNodeFamily is a new concept that allows us to implement an efficient way to solve the problem of finding a path to some ancestor node (practically reimplement ShadowNode::constructAncestorPath() in some efficient way).
This diff is the first one in the series. It introduces a new class and moves some data into it.
Reviewed By: JoshuaGross
Differential Revision: D14416947
fbshipit-source-id: c93865a8929a2128498e34d3589487696aac6283
Summary:
I am not sure why it compiled before, it clearly should not, IMO. The `const` types (and references!) are not allowed inside `std::vector` because they are not assignable.
Some experiments that I did caused compilation errors here, so I am changing that to be actually correct.
Reviewed By: JoshuaGross
Differential Revision: D14249199
fbshipit-source-id: 07a22ef13f5de9dfc7ab307493419e6006994bc2
Summary: This diff introduces the concept of "updateProps" as part of InsertMutation and it changes the diffing algorithm to populate this field.
Reviewed By: shergin
Differential Revision: D14289608
fbshipit-source-id: 642f00d03d294a12ea7fa7482c72e701b756f3d4
Summary:
It's better to comment `DWITH_FBSYSTRACE` out in BUCK files instead of removing them from the code.
I'll publish the BUCK changes as separate diff for simpler backout in the future.
Reviewed By: mdvacca
Differential Revision: D14019272
fbshipit-source-id: 8b322b5c115efe33c15929e008b97a05220813df
Summary:
`Better` is a trivial collection of basic tools borrowed from other low-level general purpose libraries (like Folly, Abseil or Boost). The main goals of Better:
- Make the codebase more portable;
- Make the dependency list explicit (by decoupling it as a dependency list of Better);
- Make relying on modern C++ patterns and tools in code simple and easy.
- Make executing experiments with different dependencies easier.
As a first example usage, this diff replaces std::unordered_map with an efficient one from folly on the one of the hottest paths.
Reviewed By: JoshuaGross
Differential Revision: D13944565
fbshipit-source-id: 5fa2c4abe6c17f7361eddcc25f968b6440d5d9db
Summary: This is a temporary change to measure production data
Reviewed By: fkgozali
Differential Revision: D13906807
fbshipit-source-id: 2a2f71aa379c4aca63c7bb4a9644704f713cb088
Summary:
ShadowView, ShadowViewMutation, and Differentiator were decoupled to separate module.
That enables us to use ShadowView more widely without facing a circular dependency problem.
Reviewed By: mdvacca
Differential Revision: D13205229
fbshipit-source-id: 7373864bf153a7813c2f97edb263a41454ce0b88