import t, c from stdint import * # ============================================================ # LinkedNode: Non-polymorphic base class (@t.NoVTable) # # Subclasses inheriting from this class gain standard linked list and tree capabilities: # - Bidirectional sibling links (next/prev) → O(1) removal # - Parent-child tree structure (child/last_child/parent) → O(1) child appending # - Child counter (child_count) # # Fields are flattened and embedded into subclasses with no vtable overhead # (equivalent to non-polymorphic inheritance in C++). # OOP methods are automatically wrapped for subclasses via _generate_inherited_method_wrappers # (self pointer cast to base type before invocation). Inherited methods can be called directly by subclasses. # # Usage: # class MyNode(LinkedNode): # value: t.CInt # root: MyNode = MyNode() # child: MyNode = MyNode() # root.append(child) # OOP invocation, self = root # child.detach() # Remove self from sibling chain # ============================================================ @t.NoVTable class LinkedNode: next: "LinkedNode" | t.CPtr # Next sibling node prev: "LinkedNode" | t.CPtr # Previous sibling node (doubly linked list, O(1) removal) child: "LinkedNode" | t.CPtr # First child node last_child: "LinkedNode" | t.CPtr # Last child node (O(1) append) parent: "LinkedNode" | t.CPtr # Parent node child_count: t.CSizeT # Number of child nodes def append(self, node: "LinkedNode" | t.CPtr): """Append node as the last child of self (O(1)). If node is already attached to any list, the caller shall invoke node.detach() prior to append. """ if self is None or node is None: return node.parent = self node.next = None node.prev = self.last_child if self.child is None: self.child = node else: self.last_child.next = node self.last_child = node self.child_count += 1 def prepend(self, node: "LinkedNode" | t.CPtr): """Insert node as the first child of self (O(1)).""" if self is None or node is None: return node.parent = self node.prev = None node.next = self.child if self.child is not None: self.child.prev = node else: self.last_child = node self.child = node self.child_count += 1 def insert_before(self, node: "LinkedNode" | t.CPtr, new_node: "LinkedNode" | t.CPtr): """Insert new_node before node (O(1)). node must be a direct child of self.""" if self is None or node is None or new_node is None: return new_node.parent = self new_node.prev = node.prev new_node.next = node if node.prev is not None: node.prev.next = new_node else: self.child = new_node node.prev = new_node self.child_count += 1 def insert_after(self, node: "LinkedNode" | t.CPtr, new_node: "LinkedNode" | t.CPtr): """Insert new_node after node (O(1)). node must be a direct child of self.""" if self is None or node is None or new_node is None: return new_node.parent = self new_node.prev = node new_node.next = node.next if node.next is not None: node.next.prev = new_node else: self.last_child = new_node node.next = new_node self.child_count += 1 def remove_child(self, node: "LinkedNode" | t.CPtr): """Remove node from self's child linked list (O(1)). The node must be a direct child of self.""" if self is None or node is None: return # Patch prev.next if node.prev is not None: node.prev.next = node.next else: self.child = node.next # Patch next.prev if node.next is not None: node.next.prev = node.prev else: self.last_child = node.prev # Clear sibling and parent links of node node.next = None node.prev = None node.parent = None if self.child_count > 0: self.child_count -= 1 def detach(self): """Detach self from its sibling linked list (O(1)). After invocation, self.next/self.prev/self.parent are cleared. The child chain remains untouched. """ if self is None: return # Patch prev.next if self.prev is not None: self.prev.next = self.next elif self.parent is not None: self.parent.child = self.next # Patch next.prev if self.next is not None: self.next.prev = self.prev elif self.parent is not None: self.parent.last_child = self.prev # Decrement parent child counter if self.parent is not None: if self.parent.child_count > 0: self.parent.child_count -= 1 # Clear links of self self.next = None self.prev = None self.parent = None def unlink(self): """Sever all links of self (siblings and parent). Child nodes are not processed recursively. After invocation, self becomes an isolated node, while its child chain still references original children (the parent field of child nodes still points to self). For full isolation, the caller shall invoke self.remove_child on each child beforehand. """ if self is None: return # First detach from sibling list self.detach() # Then break parent-child links self.child = None self.last_child = None self.child_count = 0 def has_children(self) -> t.CInt: """Return 1 if child nodes exist, otherwise return 0.""" if self is None: return 0 if self.child is not None: return 1 return 0 def child_at(self, index: t.CSizeT) -> "LinkedNode" | t.CPtr: """Return the child node at specified zero-based index (O(n)). Return None if index out of bounds.""" if self is None: return None cur: "LinkedNode" | t.CPtr = self.child i: t.CSizeT = 0 while cur is not None: if i == index: return cur i += 1 cur = cur.next return None def count_children(self) -> t.CSizeT: """Count children by traversal (O(n)), used to validate child_count.""" if self is None: return 0 n: t.CSizeT = 0 cur: "LinkedNode" | t.CPtr = self.child while cur is not None: n += 1 cur = cur.next return n def first_sibling(self) -> "LinkedNode" | t.CPtr: """Return the head node of sibling linked list (traverse backward via prev pointers).""" if self is None: return None cur: "LinkedNode" | t.CPtr = self while cur.prev is not None: cur = cur.prev return cur def last_sibling(self) -> "LinkedNode" | t.CPtr: """Return the tail node of sibling linked list (traverse forward via next pointers).""" if self is None: return None cur: "LinkedNode" | t.CPtr = self while cur.next is not None: cur = cur.next return cur # ============================================================ # SListNode: Singly linked list node (@t.NoVTable) # # Lightweight singly linked list with only Next pointer. No prev/parent/child. # Suitable for queues, stacks and simple linked structures # (such as Param/BasicBlock/Function/Line/Value in llvmlite). # O(1) append requires caller to maintain tail pointer (append_after). # O(n) append works with head pointer only (append). # ============================================================ @t.NoVTable class SListNode: Next: "SListNode" | t.CPtr # Next node def append(self, node: "SListNode" | t.CPtr) -> "SListNode" | t.CPtr: """Append node to the end of the linked list (O(n)). Return self (head). If self is None, the caller shall adopt node directly as the new head. """ if self is None: return node if node is None: return self node.Next = None cur: "SListNode" | t.CPtr = self while cur.Next is not None: cur = cur.Next cur.Next = node return self def append_after(self, node: "SListNode" | t.CPtr) -> "SListNode" | t.CPtr: """Insert node immediately after self (O(1)). Return new tail (node). Caller must maintain the head pointer manually. Return node as head if self is None. """ if node is None: return self node.Next = None if self is not None: self.Next = node return node def count(self) -> t.CSizeT: """Calculate list length via full traversal (O(n)).""" if self is None: return 0 n: t.CSizeT = 0 cur: "SListNode" | t.CPtr = self while cur is not None: n += 1 cur = cur.Next return n def at(self, index: t.CSizeT) -> "SListNode" | t.CPtr: """Return node at zero-based index (O(n)). Return None if index out of bounds.""" if self is None: return None cur: "SListNode" | t.CPtr = self i: t.CSizeT = 0 while cur is not None: if i == index: return cur i += 1 cur = cur.Next return None def remove(self, node: "SListNode" | t.CPtr) -> "SListNode" | t.CPtr: """Remove node from list (O(n)). Return updated head. The Next pointer of node will be cleared. If node is the original head, return head.Next. """ if self is None or node is None: return self if self is node: new_head: "SListNode" | t.CPtr = self.Next self.Next = None return new_head cur: "SListNode" | t.CPtr = self while cur.Next is not None: if cur.Next is node: cur.Next = node.Next node.Next = None break cur = cur.Next return self # ============================================================ # GSListNode[T]: Generic singly linked list node (@t.NoVTable + PEP 695 generics) # # Unlike SListNode (non-generic, Next: SListNode|t.CPtr), the Next field of GSListNode[T] # is typed as T|t.CPtr. After specialization it becomes a concrete node type directly, # eliminating downcasts. # # Recursive generic usage pattern (subclass inherits from self-specialized variant): # class GNode(GSListNode[GNode]): # value: t.CInt # # At this point GNode.Next: GNode|t.CPtr (strongly typed, no casting required) # # Technical validation targets: # 1. Recursive generics: class GNode(GSListNode[GNode]) # 2. Combination of @t.NoVTable attribute with generics # 3. Generic class used as field type: list: GSList[GNode] # 4. Inheritance of generic methods (GSList[T].append available after specialization) # ============================================================ @t.NoVTable class GSListNode[T]: Next: T | t.CPtr # ============================================================ # GSList[T]: Generic singly linked list container (@t.NoVTable + PEP 695 generics) # # Holds Head, Tail and Count. Provides O(1) append and O(n) indexed access. # Node type T must inherit from GSListNode[T] (to acquire the Next field). # # Usage: # list: GSList[GNode] | t.CPtr = GSList[GNode]() # list.append(node) # Method invocation, not free function # ============================================================ @t.NoVTable class GSList[T]: Head: T | t.CPtr Tail: T | t.CPtr Count: t.CSizeT def __init__(self): self.Head = None self.Tail = None self.Count = 0 def append(self, node: T): """Append node to the end of the list (O(1)).""" if node is None: return node.Next = None if self.Head is None: self.Head = node else: self.Tail.Next = node self.Tail = node self.Count += 1 def count(self) -> t.CSizeT: """Return node count (O(1)).""" return self.Count def at(self, index: t.CSizeT) -> T | t.CPtr: """Return node at zero-based index (O(n)). Return None if index out of bounds.""" if self.Head is None: return None cur: T | t.CPtr = self.Head i: t.CSizeT = 0 while cur is not None: if i == index: return cur i += 1 cur = cur.Next return None # ============================================================ # GTreeNode[T]: Generic tree node (@t.NoVTable + PEP 695 generics) # # Type-safe variant of LinkedNode. All pointer fields are typed T|t.CPtr. # Capabilities provided: # - Bidirectional sibling linked list (Next/Prev) → O(1) removal # - Parent-child tree structure (Child/LastChild/Parent) → O(1) child appending # - Child counter (Count) # # Recursive generic usage pattern (subclass inherits self-specialized variant): # @t.CVTable # class AST(GTreeNode[AST]): # def kind(self) -> t.CInt: # return 0 # # At this point AST.Next/Prev/Child/LastChild/Parent are all AST|t.CPtr (strongly typed) # # Fields are flattened and embedded into subclasses with no vtable overhead # (equivalent to non-polymorphic inheritance in C++). # If a subclass is marked @t.CVTable, it receives its own vtable (at offset 0), # and GTreeNode fields are laid out after the vtable. # # OOP methods are automatically wrapped for subclasses via _generate_inherited_method_wrappers # (self pointer cast to base type before invocation). Inherited methods can be called directly by subclasses. # ============================================================ @t.NoVTable class GTreeNode[T]: Next: T | t.CPtr # Next sibling node Prev: T | t.CPtr # Previous sibling node (doubly linked list, O(1) removal) Child: T | t.CPtr # First child node LastChild: T | t.CPtr # Last child node (O(1) append) Parent: T | t.CPtr # Parent node Count: t.CSizeT # Number of child nodes def append(self, node: T | t.CPtr): """Append node as the last child of self (O(1)). If node is already attached to any list, the caller shall invoke node.detach() prior to append. """ if self is None or node is None: return node.Parent = self node.Next = None node.Prev = self.LastChild if self.Child is None: self.Child = node else: self.LastChild.Next = node self.LastChild = node self.Count += 1 def prepend(self, node: T | t.CPtr): """Insert node as the first child of self (O(1)).""" if self is None or node is None: return node.Parent = self node.Prev = None node.Next = self.Child if self.Child is not None: self.Child.Prev = node else: self.LastChild = node self.Child = node self.Count += 1 def detach(self): """Detach self from its sibling linked list (O(1)). After invocation, self.Next/self.Prev/self.Parent are cleared. The child chain remains untouched. """ if self is None: return if self.Prev is not None: self.Prev.Next = self.Next elif self.Parent is not None: self.Parent.Child = self.Next if self.Next is not None: self.Next.Prev = self.Prev elif self.Parent is not None: self.Parent.LastChild = self.Prev if self.Parent is not None: if self.Parent.Count > 0: self.Parent.Count -= 1 self.Next = None self.Prev = None self.Parent = None def has_children(self) -> t.CInt: """Return 1 if child nodes exist, otherwise return 0.""" if self is None: return 0 if self.Child is not None: return 1 return 0 def child_at(self, index: t.CSizeT) -> T | t.CPtr: """Return the child node at specified zero-based index (O(n)). Return None if index out of bounds.""" if self is None: return None cur: T | t.CPtr = self.Child i: t.CSizeT = 0 while cur is not None: if i == index: return cur i += 1 cur = cur.Next return None def count_children(self) -> t.CSizeT: """Count children by traversal (O(n)), used to validate Count field.""" if self is None: return 0 n: t.CSizeT = 0 cur: T | t.CPtr = self.Child while cur is not None: n += 1 cur = cur.Next return n