Files
TransPyC/includes/linkedlist.vp

480 lines
17 KiB
Plaintext

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