From 178e1789b5169715a4adb9cdd0839cfe6f814859 Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Tue, 12 Jul 2022 13:34:41 +0100 Subject: [PATCH] Make AstNode::addHereThisAsNext always O(1) Using unlinkFrBackWithNext is O(n) in the size of the list if unlinking from the middle, so addHereThisAsNext also had this complexity. This patch implements addHereThisAsNext directly, which is always O(1). --- src/V3Ast.cpp | 55 ++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 50 insertions(+), 5 deletions(-) diff --git a/src/V3Ast.cpp b/src/V3Ast.cpp index 7826214d0..5518a98a8 100644 --- a/src/V3Ast.cpp +++ b/src/V3Ast.cpp @@ -631,11 +631,56 @@ void AstNode::relinkOneLink(AstNode*& pointpr, // Ref to pointer that gets set } void AstNode::addHereThisAsNext(AstNode* newp) { - // {old}->this->{next} becomes {old}->new->this->{next} - VNRelinker handle; - this->unlinkFrBackWithNext(&handle); - newp->addNext(this); - handle.relink(newp); + // {back}->this->{next} becomes {back}->new->this->{next} + UASSERT_OBJ(!newp->backp(), newp, "New node already linked?"); + UASSERT_OBJ(this->m_backp, this, "'this' node has no back, already unlinked?"); + UASSERT_OBJ(newp->m_headtailp, newp, "m_headtailp not set on new node"); + // + AstNode* const backp = this->m_backp; + AstNode* const newLastp = newp->m_headtailp; + // + this->editCountInc(); + // Common linkage + newLastp->m_nextp = this; + this->m_backp = newLastp; + newp->m_backp = backp; + // newLastp will not be the last node in the list as 'this' will follow it. + // If newLastp == newp, then below handles newp becoming head + newLastp->m_headtailp = nullptr; + // Linkage dependent on position + if (backp && backp->m_nextp == this) { + // If 'this' is not at the head of a list, then the new node will also not be at the head + // of a list, so we can just link in the new node in the middle. + backp->m_nextp = newp; + newp->m_headtailp = nullptr; + } else { + // If 'this' is at the head of a list, then the new node becomes the head of that list. + if (backp) { + if (backp->m_op1p == this) { + backp->m_op1p = newp; + } else if (backp->m_op2p == this) { + backp->m_op2p = newp; + } else if (backp->m_op3p == this) { + backp->m_op3p = newp; + } else { + UASSERT_OBJ(backp->m_op4p == this, this, "Don't know where newp should go"); + backp->m_op4p = newp; + } + } + // We also need to update m_headtailp. + AstNode* const tailp = this->m_headtailp; + this->m_headtailp = nullptr; + newp->m_headtailp = tailp; + tailp->m_headtailp = newp; + } + // Iterator fixup + if (newLastp->m_iterpp) { + *(newLastp->m_iterpp) = this; + } else if (this->m_iterpp) { + *(this->m_iterpp) = newp; + } + // + debugTreeChange(this, "-addHereThisAsNext: ", __LINE__, true); } void AstNode::swapWith(AstNode* bp) {