diff --git a/src/bake/DevServer.zig b/src/bake/DevServer.zig index 78bedb78ba..73b3fe9874 100644 --- a/src/bake/DevServer.zig +++ b/src/bake/DevServer.zig @@ -1824,7 +1824,7 @@ const DeferredRequest = struct { /// is very silly. This contributes to ~6kb of the initial DevServer allocation. const max_preallocated = 16; - pub const List = std.SinglyLinkedList(DeferredRequest); + pub const List = bun.SinglyLinkedList(DeferredRequest); pub const Node = List.Node; route_bundle_index: RouteBundle.Index, diff --git a/src/bun.zig b/src/bun.zig index 72e9fcf79b..99a48e8122 100644 --- a/src/bun.zig +++ b/src/bun.zig @@ -176,6 +176,8 @@ pub const comptime_string_map = @import("./comptime_string_map.zig"); pub const ComptimeStringMap = comptime_string_map.ComptimeStringMap; pub const ComptimeStringMap16 = comptime_string_map.ComptimeStringMap16; pub const ComptimeStringMapWithKeyType = comptime_string_map.ComptimeStringMapWithKeyType; +// Old version of SinglyLinkedList +pub const SinglyLinkedList = @import("./linked_list.zig").SinglyLinkedList; pub const glob = @import("./glob.zig"); pub const patch = @import("./patch.zig"); @@ -2849,7 +2851,7 @@ pub fn runtimeEmbedFile( abs_path, std.math.maxInt(usize), null, - @alignOf(u8), + .fromByteUnits(@alignOf(u8)), '\x00', ) catch |e| { Output.panic( diff --git a/src/json_parser.zig b/src/json_parser.zig index 5ad14e854b..b542a59345 100644 --- a/src/json_parser.zig +++ b/src/json_parser.zig @@ -27,7 +27,7 @@ const LEXER_DEBUGGER_WORKAROUND = false; const HashMapPool = struct { const HashMap = std.HashMap(u64, void, IdentityContext, 80); - const LinkedList = std.SinglyLinkedList(HashMap); + const LinkedList = bun.SinglyLinkedList(HashMap); threadlocal var list: LinkedList = undefined; threadlocal var loaded: bool = false; diff --git a/src/linked_list.zig b/src/linked_list.zig new file mode 100644 index 0000000000..65361ad728 --- /dev/null +++ b/src/linked_list.zig @@ -0,0 +1,124 @@ +// 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; + } + } + }; +} diff --git a/src/sync.zig b/src/sync.zig index ea63c40920..1f0b524048 100644 --- a/src/sync.zig +++ b/src/sync.zig @@ -1106,7 +1106,7 @@ else struct { mutex: Mutex, notified: bool, - waiters: std.SinglyLinkedList(Event), + waiters: bun.SinglyLinkedList(Event), pub fn init() Condvar { return .{ diff --git a/src/toml/toml_parser.zig b/src/toml/toml_parser.zig index a483e18c4d..c48888c75d 100644 --- a/src/toml/toml_parser.zig +++ b/src/toml/toml_parser.zig @@ -20,7 +20,7 @@ const IdentityContext = @import("../identity_context.zig").IdentityContext; const HashMapPool = struct { const HashMap = std.HashMap(u64, void, IdentityContext, 80); - const LinkedList = std.SinglyLinkedList(HashMap); + const LinkedList = bun.SinglyLinkedList(HashMap); threadlocal var list: LinkedList = undefined; threadlocal var loaded: bool = false;