diff --git a/detach-link-notes.md b/detach-link-notes.md new file mode 100644 index 0000000..2fc5d84 --- /dev/null +++ b/detach-link-notes.md @@ -0,0 +1,54 @@ +* D E F +* A B C + +`E.insertAfter(B) ->` + +* D F +* A B E C + +* B + * _next_ = C + * prev = A + +* C + * next = null + * _prev_ = B + +* E + * _next_ = F + * _prev_ = D + * _parent_ = ??? + +* D + * _next_ = E + * _prev_ = F + +* F + * next = null + * _prev_ = E + +italic properties must change. + +```D +// first, fix old nodes. +if(E == E.parent.firstChild) // nope + // E.prev must be null if this is true, short circuit logic? + E.parent.firstChild = E.next; +if(E == E.parent.lastChild) // nope + // E.next must be null if this is true, short circuit logic? + E.parent.lastChild = E.prev; +if(E.next) // F + E.next.prev = E.prev; +if(E.prev) // D + E.prev.next = E.next; +// insertBefore is an exact mirror of this beyond this point, and identical before. +// the links on E are free to scram now +E.prev = B; +E.next = B.next; + +// now, set links to E + +if(B.next) // C + B.next.prev = E; +B.next = E; +``` diff --git a/src/html/dom.d b/src/html/dom.d index 068c00a..87f05e1 100644 --- a/src/html/dom.d +++ b/src/html/dom.d @@ -313,8 +313,8 @@ struct Node { assert(document_ == node.document_); assert(isElementNode, "cannot prepend to non-element nodes"); - if (node.parent_) - node.detach(); + node.detachFast(); + node.parent_ = &this; if (firstChild_) { assert(!firstChild_.prev_); @@ -325,15 +325,20 @@ struct Node { assert(!lastChild_); firstChild_ = node; lastChild_ = node; + lastChild_.next_ = null; } + if(firstChild_.prev_) { + firstChild_.prev_.next_ = null; + firstChild_.prev_ = null; + } } void appendChild(Node* node) { assert(document_ == node.document_); assert(isElementNode, "cannot append to non-element nodes"); - if (node.parent_) - node.detach(); + node.detachFast(); + node.parent_ = &this; if (lastChild_) { assert(!lastChild_.next_); @@ -343,8 +348,13 @@ struct Node { } else { assert(!firstChild_); firstChild_ = node; + firstChild_.prev_ = null; lastChild_ = node; } + if(lastChild.next_) { + lastChild.next_.prev_ = null; + lastChild_.next_ = null; + } } void removeChild(Node* node) { @@ -391,89 +401,110 @@ struct Node { firstChild_ = node; lastChild_ = node; } + lastChild_.next_ = null; node.parent_ = &this; } void insertBefore(Node* node) { assert(document_ == node.document_); + assert(node); + detachFast(); parent_ = node.parent_; prev_ = node.prev_; next_ = node; node.prev_ = &this; - if (parent_ && (parent_.firstChild_ == node)) - parent_.firstChild_ = &this; + if (parent_ && (parent_.firstChild_ == node)) { + assert(!prev_); + parent_.firstChild_ = &this; + } else if(prev_) { + prev_.next_ = &this; + } } void insertAfter(Node* node) { assert(document_ == node.document_); + detachFast(); parent_ = node.parent_; prev_ = node; next_ = node.next_; node.next_ = &this; + if(parent_ && (parent_.lastChild_ == node)) { + assert(!next_); + parent_.lastChild_ = &this; + } else if(next_) { + next_.prev_ = &this; + } } - void detach() { + private void packageDetach(bool careful)() { if (parent_) { if (parent_.firstChild_ == &this) { parent_.firstChild_ = next_; if (next_) { next_.prev_ = null; - next_ = null; + static if(careful) { + next_ = null; + } } else { parent_.lastChild_ = null; } - assert(prev_ == null); + static if(careful) { + assert(prev_ == null); + } } else if (parent_.lastChild_ == &this) { parent_.lastChild_ = prev_; assert(prev_); - assert(!next_); + assert(next_ is null); prev_.next_ = null; - prev_ = null; + static if(careful) { + prev_ = null; + } } else { assert(prev_); prev_.next_ = next_; + static if(careful) { + prev_ = null; + } if (next_) { next_.prev_ = prev_; - next_ = null; + static if(careful) { + next_ = null; + } } + } + } else { + static if(careful) { + if(prev_) { + prev_.next_ = next_; + static if(careful) { prev_ = null; + } } - parent_ = null; - } - } - - package void detachFast() { - if (parent_) { - if (parent_.firstChild_ == &this) { - parent_.firstChild_ = next_; - if (next_) { - next_.prev_ = null; - } else { - parent_.lastChild_ = null; - } - - assert(prev_ == null); - } else if (parent_.lastChild_ == &this) { - parent_.lastChild_ = prev_; - assert(prev_); - assert(!next_); - prev_.next_ = null; - } else { - assert(prev_); - - prev_.next_ = next_; - if (next_) { - next_.prev_ = prev_; - } + if(next_) { + next_.prev_ = prev_; + static if(careful) { + next_ = null; + } } + } else { + assert(prev_ is null); + assert(next_ is null); + } } + static if(careful) { + assert(prev_ is null); + assert(next_ is null); + } } + public alias detach = packageDetach!true; + package alias detachFast = packageDetach!false; + void destroy() { detachFast(); destroyChildren();