SinglyLinkedList

This commit is contained in:
pfg
2025-06-18 20:39:33 -07:00
parent b178ccd011
commit da48da4ae3
6 changed files with 131 additions and 5 deletions

View File

@@ -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,

View File

@@ -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(

View File

@@ -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;

124
src/linked_list.zig Normal file
View File

@@ -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;
}
}
};
}

View File

@@ -1106,7 +1106,7 @@ else
struct {
mutex: Mutex,
notified: bool,
waiters: std.SinglyLinkedList(Event),
waiters: bun.SinglyLinkedList(Event),
pub fn init() Condvar {
return .{

View File

@@ -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;