Fabric: ShadowNode::children_ is now managed in copy-on-write manner
Summary: @public ShadowNode class is designed to share `props` and `children` objects between instances. Given that all *Props classes are immutable, it's very easy to share them and we do this from the day one. The `children_` collection is more tricky though because ShadowNode class has a couple of mutation methods. Previously, we dealt with it very simply by copying the whole vector in constructors, and that was far from optimal. Now we store a special flag that indicates that the children list is shared among nodes, and we clone this before the first mutation. Sharing a `shared_ptr` should be much more efficient (cost of atomic refcount increment) than instantiating whole new collection (an allocation). Reviewed By: mdvacca Differential Revision: D8988386 fbshipit-source-id: cb2f6b2fccac70a35e070a1aa108d135f77cd041
This commit is contained in:
parent
d74346b616
commit
938e1d51c4
|
@ -30,9 +30,14 @@ ShadowNode::ShadowNode(
|
|||
rootTag_(fragment.rootTag),
|
||||
props_(fragment.props),
|
||||
eventEmitter_(fragment.eventEmitter),
|
||||
children_(std::make_shared<SharedShadowNodeList>(*fragment.children)),
|
||||
children_(fragment.children ?: emptySharedShadowNodeSharedList()),
|
||||
cloneFunction_(cloneFunction),
|
||||
revision_(1) {}
|
||||
childrenAreShared_(true),
|
||||
revision_(1) {
|
||||
|
||||
assert(props_);
|
||||
assert(children_);
|
||||
}
|
||||
|
||||
ShadowNode::ShadowNode(
|
||||
const SharedShadowNode &sourceShadowNode,
|
||||
|
@ -42,10 +47,15 @@ ShadowNode::ShadowNode(
|
|||
rootTag_(fragment.rootTag ?: sourceShadowNode->rootTag_),
|
||||
props_(fragment.props ?: sourceShadowNode->props_),
|
||||
eventEmitter_(fragment.eventEmitter ?: sourceShadowNode->eventEmitter_),
|
||||
children_(std::make_shared<SharedShadowNodeList>(*(fragment.children ?: sourceShadowNode->children_))),
|
||||
children_(fragment.children ?: sourceShadowNode->children_),
|
||||
localData_(fragment.localData ?: sourceShadowNode->localData_),
|
||||
cloneFunction_(sourceShadowNode->cloneFunction_),
|
||||
revision_(sourceShadowNode->revision_ + 1) {}
|
||||
childrenAreShared_(true),
|
||||
revision_(sourceShadowNode->revision_ + 1) {
|
||||
|
||||
assert(props_);
|
||||
assert(children_);
|
||||
}
|
||||
|
||||
UnsharedShadowNode ShadowNode::clone(const ShadowNodeFragment &fragment) const {
|
||||
assert(cloneFunction_);
|
||||
|
@ -97,6 +107,7 @@ void ShadowNode::sealRecursive() const {
|
|||
void ShadowNode::appendChild(const SharedShadowNode &child) {
|
||||
ensureUnsealed();
|
||||
|
||||
cloneChildrenIfShared();
|
||||
auto nonConstChildren = std::const_pointer_cast<SharedShadowNodeList>(children_);
|
||||
nonConstChildren->push_back(child);
|
||||
}
|
||||
|
@ -104,6 +115,8 @@ void ShadowNode::appendChild(const SharedShadowNode &child) {
|
|||
void ShadowNode::replaceChild(const SharedShadowNode &oldChild, const SharedShadowNode &newChild, int suggestedIndex) {
|
||||
ensureUnsealed();
|
||||
|
||||
cloneChildrenIfShared();
|
||||
|
||||
auto nonConstChildren = std::const_pointer_cast<SharedShadowNodeList>(children_);
|
||||
|
||||
if (suggestedIndex != -1 && suggestedIndex < nonConstChildren->size()) {
|
||||
|
@ -121,6 +134,14 @@ void ShadowNode::setLocalData(const SharedLocalData &localData) {
|
|||
localData_ = localData;
|
||||
}
|
||||
|
||||
void ShadowNode::cloneChildrenIfShared() {
|
||||
if (!childrenAreShared_) {
|
||||
return;
|
||||
}
|
||||
childrenAreShared_ = false;
|
||||
children_ = std::make_shared<SharedShadowNodeList>(*children_);
|
||||
}
|
||||
|
||||
#pragma mark - Equality
|
||||
|
||||
bool ShadowNode::operator==(const ShadowNode& rhs) const {
|
||||
|
|
|
@ -137,12 +137,24 @@ protected:
|
|||
|
||||
private:
|
||||
|
||||
/*
|
||||
* Clones the list of children (and creates a new `shared_ptr` to it) if
|
||||
* `childrenAreShared_` flag is `true`.
|
||||
*/
|
||||
void cloneChildrenIfShared();
|
||||
|
||||
/*
|
||||
* A reference to a cloning function that understands how to clone
|
||||
* the specific type of ShadowNode.
|
||||
*/
|
||||
ShadowNodeCloneFunction cloneFunction_;
|
||||
|
||||
/*
|
||||
* Indicates that `children` list is shared between nodes and need
|
||||
* to be cloned before the first mutation.
|
||||
*/
|
||||
bool childrenAreShared_;
|
||||
|
||||
/*
|
||||
* A number of the generation of the ShadowNode instance;
|
||||
* is used and useful for debug-printing purposes *only*.
|
||||
|
|
Loading…
Reference in New Issue