// TODO(zig-upgrade): Migrate to the new intrusive list /// A singly-linked list is headed by a single forward pointer. The elements /// are singly-linked for minimum space and pointer manipulation overhead at /// the expense of O(n) removal for arbitrary elements. New elements can be /// added to the list after an existing element or at the head of the list. /// A singly-linked list may only be traversed in the forward direction. /// Singly-linked lists are ideal for applications with large datasets and /// few or no removals or for implementing a LIFO queue. pub fn SinglyLinkedList(comptime T: type) type { return struct { const Self = @This(); /// Node inside the linked list wrapping the actual data. pub const Node = struct { next: ?*Node = null, data: T, pub const Data = T; /// Insert a new node after the current one. /// /// Arguments: /// new_node: Pointer to the new node to insert. pub fn insertAfter(node: *Node, new_node: *Node) void { new_node.next = node.next; node.next = new_node; } /// Remove a node from the list. /// /// Arguments: /// node: Pointer to the node to be removed. /// Returns: /// node removed pub fn removeNext(node: *Node) ?*Node { const next_node = node.next orelse return null; node.next = next_node.next; return next_node; } /// Iterate over the singly-linked list from this node, until the final node is found. /// This operation is O(N). pub fn findLast(node: *Node) *Node { var it = node; while (true) { it = it.next orelse return it; } } /// Iterate over each next node, returning the count of all nodes except the starting one. /// This operation is O(N). pub fn countChildren(node: *const Node) usize { var count: usize = 0; var it: ?*const Node = node.next; while (it) |n| : (it = n.next) { count += 1; } return count; } /// Reverse the list starting from this node in-place. /// This operation is O(N). pub fn reverse(indirect: *?*Node) void { if (indirect.* == null) { return; } var current: *Node = indirect.*.?; while (current.next) |next| { current.next = next.next; next.next = indirect.*; indirect.* = next; } } }; first: ?*Node = null, /// Insert a new node at the head. /// /// Arguments: /// new_node: Pointer to the new node to insert. pub fn prepend(list: *Self, new_node: *Node) void { new_node.next = list.first; list.first = new_node; } /// Remove a node from the list. /// /// Arguments: /// node: Pointer to the node to be removed. pub fn remove(list: *Self, node: *Node) void { if (list.first == node) { list.first = node.next; } else { var current_elm = list.first.?; while (current_elm.next != node) { current_elm = current_elm.next.?; } current_elm.next = node.next; } } /// Remove and return the first node in the list. /// /// Returns: /// A pointer to the first node in the list. pub fn popFirst(list: *Self) ?*Node { const first = list.first orelse return null; list.first = first.next; return first; } /// Iterate over all nodes, returning the count. /// This operation is O(N). pub fn len(list: Self) usize { if (list.first) |n| { return 1 + n.countChildren(); } else { return 0; } } }; }