[poincare] Automatically detach a tree before adding it

This commit is contained in:
Léa Saviot
2018-08-31 10:23:52 +02:00
parent 79dd0919f2
commit fb3d34cf2b
8 changed files with 45 additions and 1 deletions

View File

@@ -44,6 +44,7 @@ public:
m_numberOfChildren-= decrement;
}
void eraseNumberOfChildren() override { m_numberOfChildren = 0; }
void childAtIndexWillBeStolen(int index) override;
#if POINCARE_TREE_LOG
virtual void logNodeName(std::ostream & stream) const override {
stream << "HorizontalLayout";

View File

@@ -17,6 +17,7 @@ public:
m_numberOfChildren-= decrement;
}
void eraseNumberOfChildren() override { m_numberOfChildren = 0; }
void childAtIndexWillBeStolen(int index) override;
// Comparison
typedef int (*ExpressionOrder)(const ExpressionNode * e1, const ExpressionNode * e2, bool canBeInterrupted);

View File

@@ -83,6 +83,9 @@ public:
int indexOfChild(TreeByReference t) const {
return node()->indexOfChild(t.node());
}
void childAtIndexWillBeStolen(int index) {
node()->childAtIndexWillBeStolen(index);
}
/* Hierarchy operations */
// Replace
@@ -90,6 +93,10 @@ public:
void replaceChildInPlace(TreeByReference oldChild, TreeByReference newChild);
void replaceChildAtIndexInPlace(int oldChildIndex, TreeByReference newChild);
void replaceWithAllocationFailureInPlace(int currentNumberOfChildren);
void replaceChildAtIndexWithGhostInPlace(int index) {
assert(index >= 0 && index < numberOfChildren());
replaceChildWithGhostInPlace(childAtIndex(index));
}
void replaceChildWithGhostInPlace(TreeByReference t);
// Merge
void mergeChildrenAtIndexInPlace(TreeByReference t, int i);
@@ -124,6 +131,7 @@ protected:
int m_identifier;
private:
void detachFromParent();
// Add ghost children on layout construction
void buildGhostChildren();
};

View File

@@ -69,6 +69,8 @@ public:
bool hasChild(const TreeNode * child) const;
bool hasAncestor(const TreeNode * node, bool includeSelf) const;
bool hasSibling(const TreeNode * e) const;
// Prepare a child that will be stolen by another Expression
virtual void childAtIndexWillBeStolen(int index);
// AddChild collateral effect
virtual void didAddChildAtIndex(int newNumberOfChildren) {}

View File

@@ -193,6 +193,10 @@ bool HorizontalLayoutNode::hasText() const {
return true;
}
void HorizontalLayoutNode::childAtIndexWillBeStolen(int index) {
HorizontalLayoutRef(this).removeChildAtIndex(index, nullptr);
}
// Protected
KDSize HorizontalLayoutNode::computeSize() {

View File

@@ -36,6 +36,10 @@ Expression NAryExpressionNode::squashUnaryHierarchy() {
return copy;
}
void NAryExpressionNode::childAtIndexWillBeStolen(int index) {
NAryExpression(this).removeChildAtIndexInPlace(index);
}
// Private
int NAryExpressionNode::simplificationOrderSameType(const ExpressionNode * e, bool canBeInterrupted) const {

View File

@@ -68,6 +68,9 @@ void TreeByReference::replaceChildInPlace(TreeByReference oldChild, TreeByRefere
return;
}
// If the new child has a parent, detach from it
newChild.detachFromParent();
// Move the new child
assert(newChild.isGhost() || newChild.parent().isUninitialized());
TreePool::sharedPool()->move(oldChild.node(), newChild.node(), newChild.numberOfChildren());
@@ -144,6 +147,10 @@ void TreeByReference::replaceChildWithGhostInPlace(TreeByReference t) {
}
void TreeByReference::mergeChildrenAtIndexInPlace(TreeByReference t, int i) {
/* mergeChildrenAtIndexInPlace should only be called with a tree thant can
* have any number of children, so there is no need to replace the stolen
* children with ghosts. */
// TODO assert this and t are "dynamic" trees
assert(i >= 0 && i <= numberOfChildren());
// Steal operands
int numberOfNewChildren = t.numberOfChildren();
@@ -196,8 +203,8 @@ void TreeByReference::addChildAtIndexInPlace(TreeByReference t, int index, int c
replaceWithAllocationFailureInPlace(currentNumberOfChildren);
return;
}
assert(index >= 0 && index <= currentNumberOfChildren);
assert(t.parent().isUninitialized());
// If the new node is static, copy it in the pool and add the copy
if (t.isStatic()) {
@@ -210,6 +217,10 @@ void TreeByReference::addChildAtIndexInPlace(TreeByReference t, int index, int c
return;
}
// If t has a parent, detach t from it.
t.detachFromParent();
assert(t.parent().isUninitialized());
// Move t
TreeNode * newChildPosition = node()->next();
for (int i = 0; i < index; i++) {
@@ -251,6 +262,15 @@ void TreeByReference::removeChildrenInPlace(int currentNumberOfChildren) {
/* Private */
void TreeByReference::detachFromParent() {
TreeByReference myParent = parent();
if (!myParent.isUninitialized()) {
int idxInParent = myParent.indexOfChild(*this);
myParent.childAtIndexWillBeStolen(idxInParent);
}
assert(parent().isUninitialized());
}
void TreeByReference::setTo(const TreeByReference & tr) {
/* We cannot use (*this)==tr because tr would need to be casted to
* TreeByReference, which calls setTo and triggers an infinite loop */

View File

@@ -192,6 +192,10 @@ TreeNode * TreeNode::nextSibling() const {
return node;
}
void TreeNode::childAtIndexWillBeStolen(int index) {
TreeByReference(this).replaceChildAtIndexWithGhostInPlace(index);
}
TreeNode * TreeNode::lastDescendant() const {
TreeNode * node = const_cast<TreeNode *>(this);
int remainingNodesToVisit = node->numberOfChildren();