| author | |
| committer | |
| log | 12b2950bf294b3cfda0616b2e71b739cbda684d9 |
| tree | 25a5a2da7a6527cf61096e236baf26c58d1ccc05 |
| parent | b7811d32690a9f3b4912635e16e6aa5ace25362c |
| parent | b0648bfbd31cad73e00ee72b430dcf2c2907e08f |
| signature |
Add SinglyLinkedList8 files changed, 205 insertions(+), 21 deletions(-)
src-self-hosted/compilation.zig+1-1| ... | @@ -160,7 +160,7 @@ pub const Compilation = struct { | ... | @@ -160,7 +160,7 @@ pub const Compilation = struct { |
| 160 | /// it uses an optional pointer so that tombstone removals are possible | 160 | /// it uses an optional pointer so that tombstone removals are possible |
| 161 | fn_link_set: event.Locked(FnLinkSet), | 161 | fn_link_set: event.Locked(FnLinkSet), |
| 162 | 162 | ||
| 163 | pub const FnLinkSet = std.LinkedList(?*Value.Fn); | 163 | pub const FnLinkSet = std.TailQueue(?*Value.Fn); |
| 164 | 164 | ||
| 165 | windows_subsystem_windows: bool, | 165 | windows_subsystem_windows: bool, |
| 166 | windows_subsystem_console: bool, | 166 | windows_subsystem_console: bool, |
src-self-hosted/value.zig+1-1| ... | @@ -186,7 +186,7 @@ pub const Value = struct { | ... | @@ -186,7 +186,7 @@ pub const Value = struct { |
| 186 | /// Path to the object file that contains this function | 186 | /// Path to the object file that contains this function |
| 187 | containing_object: Buffer, | 187 | containing_object: Buffer, |
| 188 | 188 | ||
| 189 | link_set_node: *std.LinkedList(?*Value.Fn).Node, | 189 | link_set_node: *std.TailQueue(?*Value.Fn).Node, |
| 190 | 190 | ||
| 191 | /// Creates a Fn value with 1 ref | 191 | /// Creates a Fn value with 1 ref |
| 192 | /// Takes ownership of symbol_name | 192 | /// Takes ownership of symbol_name |
std/atomic/queue.zig+1-1| ... | @@ -14,7 +14,7 @@ pub fn Queue(comptime T: type) type { | ... | @@ -14,7 +14,7 @@ pub fn Queue(comptime T: type) type { |
| 14 | mutex: std.Mutex, | 14 | mutex: std.Mutex, |
| 15 | 15 | ||
| 16 | pub const Self = @This(); | 16 | pub const Self = @This(); |
| 17 | pub const Node = std.LinkedList(T).Node; | 17 | pub const Node = std.TailQueue(T).Node; |
| 18 | 18 | ||
| 19 | pub fn init() Self { | 19 | pub fn init() Self { |
| 20 | return Self{ | 20 | return Self{ |
std/child_process.zig+3-3| ... | @@ -13,7 +13,7 @@ const BufMap = std.BufMap; | ... | @@ -13,7 +13,7 @@ const BufMap = std.BufMap; |
| 13 | const Buffer = std.Buffer; | 13 | const Buffer = std.Buffer; |
| 14 | const builtin = @import("builtin"); | 14 | const builtin = @import("builtin"); |
| 15 | const Os = builtin.Os; | 15 | const Os = builtin.Os; |
| 16 | const LinkedList = std.LinkedList; | 16 | const TailQueue = std.TailQueue; |
| 17 | const maxInt = std.math.maxInt; | 17 | const maxInt = std.math.maxInt; |
| 18 | 18 | ||
| 19 | pub const ChildProcess = struct { | 19 | pub const ChildProcess = struct { |
| ... | @@ -48,7 +48,7 @@ pub const ChildProcess = struct { | ... | @@ -48,7 +48,7 @@ pub const ChildProcess = struct { |
| 48 | pub cwd: ?[]const u8, | 48 | pub cwd: ?[]const u8, |
| 49 | 49 | ||
| 50 | err_pipe: if (os.windows.is_the_target) void else [2]os.fd_t, | 50 | err_pipe: if (os.windows.is_the_target) void else [2]os.fd_t, |
| 51 | llnode: if (os.windows.is_the_target) void else LinkedList(*ChildProcess).Node, | 51 | llnode: if (os.windows.is_the_target) void else TailQueue(*ChildProcess).Node, |
| 52 | 52 | ||
| 53 | pub const SpawnError = error{OutOfMemory} || os.ExecveError || os.SetIdError || | 53 | pub const SpawnError = error{OutOfMemory} || os.ExecveError || os.SetIdError || |
| 54 | os.ChangeCurDirError || windows.CreateProcessError; | 54 | os.ChangeCurDirError || windows.CreateProcessError; |
| ... | @@ -388,7 +388,7 @@ pub const ChildProcess = struct { | ... | @@ -388,7 +388,7 @@ pub const ChildProcess = struct { |
| 388 | 388 | ||
| 389 | self.pid = pid; | 389 | self.pid = pid; |
| 390 | self.err_pipe = err_pipe; | 390 | self.err_pipe = err_pipe; |
| 391 | self.llnode = LinkedList(*ChildProcess).Node.init(self); | 391 | self.llnode = TailQueue(*ChildProcess).Node.init(self); |
| 392 | self.term = null; | 392 | self.term = null; |
| 393 | 393 | ||
| 394 | if (self.stdin_behavior == StdIo.Pipe) { | 394 | if (self.stdin_behavior == StdIo.Pipe) { |
std/event/net.zig+1-1| ... | @@ -19,7 +19,7 @@ pub const Server = struct { | ... | @@ -19,7 +19,7 @@ pub const Server = struct { |
| 19 | waiting_for_emfile_node: PromiseNode, | 19 | waiting_for_emfile_node: PromiseNode, |
| 20 | listen_resume_node: event.Loop.ResumeNode, | 20 | listen_resume_node: event.Loop.ResumeNode, |
| 21 | 21 | ||
| 22 | const PromiseNode = std.LinkedList(promise).Node; | 22 | const PromiseNode = std.TailQueue(promise).Node; |
| 23 | 23 | ||
| 24 | pub fn init(loop: *Loop) Server { | 24 | pub fn init(loop: *Loop) Server { |
| 25 | // TODO can't initialize handler coroutine here because we need well defined copy elision | 25 | // TODO can't initialize handler coroutine here because we need well defined copy elision |
std/heap.zig+5-6| ... | @@ -347,10 +347,10 @@ pub const ArenaAllocator = struct { | ... | @@ -347,10 +347,10 @@ pub const ArenaAllocator = struct { |
| 347 | pub allocator: Allocator, | 347 | pub allocator: Allocator, |
| 348 | 348 | ||
| 349 | child_allocator: *Allocator, | 349 | child_allocator: *Allocator, |
| 350 | buffer_list: std.LinkedList([]u8), | 350 | buffer_list: std.SinglyLinkedList([]u8), |
| 351 | end_index: usize, | 351 | end_index: usize, |
| 352 | 352 | ||
| 353 | const BufNode = std.LinkedList([]u8).Node; | 353 | const BufNode = std.SinglyLinkedList([]u8).Node; |
| 354 | 354 | ||
| 355 | pub fn init(child_allocator: *Allocator) ArenaAllocator { | 355 | pub fn init(child_allocator: *Allocator) ArenaAllocator { |
| 356 | return ArenaAllocator{ | 356 | return ArenaAllocator{ |
| ... | @@ -359,7 +359,7 @@ pub const ArenaAllocator = struct { | ... | @@ -359,7 +359,7 @@ pub const ArenaAllocator = struct { |
| 359 | .shrinkFn = shrink, | 359 | .shrinkFn = shrink, |
| 360 | }, | 360 | }, |
| 361 | .child_allocator = child_allocator, | 361 | .child_allocator = child_allocator, |
| 362 | .buffer_list = std.LinkedList([]u8).init(), | 362 | .buffer_list = std.SinglyLinkedList([]u8).init(), |
| 363 | .end_index = 0, | 363 | .end_index = 0, |
| 364 | }; | 364 | }; |
| 365 | } | 365 | } |
| ... | @@ -387,10 +387,9 @@ pub const ArenaAllocator = struct { | ... | @@ -387,10 +387,9 @@ pub const ArenaAllocator = struct { |
| 387 | const buf_node = &buf_node_slice[0]; | 387 | const buf_node = &buf_node_slice[0]; |
| 388 | buf_node.* = BufNode{ | 388 | buf_node.* = BufNode{ |
| 389 | .data = buf, | 389 | .data = buf, |
| 390 | .prev = null, | ||
| 391 | .next = null, | 390 | .next = null, |
| 392 | }; | 391 | }; |
| 393 | self.buffer_list.append(buf_node); | 392 | self.buffer_list.prepend(buf_node); |
| 394 | self.end_index = 0; | 393 | self.end_index = 0; |
| 395 | return buf_node; | 394 | return buf_node; |
| 396 | } | 395 | } |
| ... | @@ -398,7 +397,7 @@ pub const ArenaAllocator = struct { | ... | @@ -398,7 +397,7 @@ pub const ArenaAllocator = struct { |
| 398 | fn alloc(allocator: *Allocator, n: usize, alignment: u29) ![]u8 { | 397 | fn alloc(allocator: *Allocator, n: usize, alignment: u29) ![]u8 { |
| 399 | const self = @fieldParentPtr(ArenaAllocator, "allocator", allocator); | 398 | const self = @fieldParentPtr(ArenaAllocator, "allocator", allocator); |
| 400 | 399 | ||
| 401 | var cur_node = if (self.buffer_list.last) |last_node| last_node else try self.createNode(0, n + alignment); | 400 | var cur_node = if (self.buffer_list.first) |first_node| first_node else try self.createNode(0, n + alignment); |
| 402 | while (true) { | 401 | while (true) { |
| 403 | const cur_buf = cur_node.data[@sizeOf(BufNode)..]; | 402 | const cur_buf = cur_node.data[@sizeOf(BufNode)..]; |
| 404 | const addr = @ptrToInt(cur_buf.ptr) + self.end_index; | 403 | const addr = @ptrToInt(cur_buf.ptr) + self.end_index; |
std/linked_list.zig+191-7| ... | @@ -5,8 +5,192 @@ const testing = std.testing; | ... | @@ -5,8 +5,192 @@ const testing = std.testing; |
| 5 | const mem = std.mem; | 5 | const mem = std.mem; |
| 6 | const Allocator = mem.Allocator; | 6 | const Allocator = mem.Allocator; |
| 7 | 7 | ||
| 8 | /// Generic doubly linked list. | 8 | /// A singly-linked list is headed by a single forward pointer. The elements |
| 9 | pub fn LinkedList(comptime T: type) type { | 9 | /// are singly linked for minimum space and pointer manipulation overhead at |
| 10 | /// the expense of O(n) removal for arbitrary elements. New elements can be | ||
| 11 | /// added to the list after an existing element or at the head of the list. | ||
| 12 | /// A singly-linked list may only be traversed in the forward direction. | ||
| 13 | /// Singly-linked lists are ideal for applications with large datasets and | ||
| 14 | /// few or no removals or for implementing a LIFO queue. | ||
| 15 | pub fn SinglyLinkedList(comptime T: type) type { | ||
| 16 | return struct { | ||
| 17 | const Self = @This(); | ||
| 18 | |||
| 19 | /// Node inside the linked list wrapping the actual data. | ||
| 20 | pub const Node = struct { | ||
| 21 | next: ?*Node, | ||
| 22 | data: T, | ||
| 23 | |||
| 24 | pub fn init(data: T) Node { | ||
| 25 | return Node{ | ||
| 26 | .next = null, | ||
| 27 | .data = data, | ||
| 28 | }; | ||
| 29 | } | ||
| 30 | |||
| 31 | /// Insert a new node after the current one. | ||
| 32 | /// | ||
| 33 | /// Arguments: | ||
| 34 | /// new_node: Pointer to the new node to insert. | ||
| 35 | pub fn insertAfter(node: *Node, new_node: *Node) void { | ||
| 36 | new_node.next = node.next; | ||
| 37 | node.next = new_node; | ||
| 38 | } | ||
| 39 | |||
| 40 | /// Remove a node from the list. | ||
| 41 | /// | ||
| 42 | /// Arguments: | ||
| 43 | /// node: Pointer to the node to be removed. | ||
| 44 | /// Returns: | ||
| 45 | /// node removed | ||
| 46 | pub fn removeNext(node: *Node) ?*Node { | ||
| 47 | const next_node = node.next orelse return null; | ||
| 48 | node.next = next_node.next; | ||
| 49 | return next_node; | ||
| 50 | } | ||
| 51 | }; | ||
| 52 | |||
| 53 | first: ?*Node, | ||
| 54 | |||
| 55 | /// Initialize a linked list. | ||
| 56 | /// | ||
| 57 | /// Returns: | ||
| 58 | /// An empty linked list. | ||
| 59 | pub fn init() Self { | ||
| 60 | return Self{ | ||
| 61 | .first = null, | ||
| 62 | }; | ||
| 63 | } | ||
| 64 | |||
| 65 | /// Insert a new node after an existing one. | ||
| 66 | /// | ||
| 67 | /// Arguments: | ||
| 68 | /// node: Pointer to a node in the list. | ||
| 69 | /// new_node: Pointer to the new node to insert. | ||
| 70 | pub fn insertAfter(list: *Self, node: *Node, new_node: *Node) void { | ||
| 71 | node.insertAfter(new_node); | ||
| 72 | } | ||
| 73 | |||
| 74 | /// Insert a new node at the head. | ||
| 75 | /// | ||
| 76 | /// Arguments: | ||
| 77 | /// new_node: Pointer to the new node to insert. | ||
| 78 | pub fn prepend(list: *Self, new_node: *Node) void { | ||
| 79 | new_node.next = list.first; | ||
| 80 | list.first = new_node; | ||
| 81 | } | ||
| 82 | |||
| 83 | /// Remove a node from the list. | ||
| 84 | /// | ||
| 85 | /// Arguments: | ||
| 86 | /// node: Pointer to the node to be removed. | ||
| 87 | pub fn remove(list: *Self, node: *Node) void { | ||
| 88 | if (list.first == node) { | ||
| 89 | list.first = node.next; | ||
| 90 | } else { | ||
| 91 | var current_elm = list.first.?; | ||
| 92 | while (current_elm.next != node) { | ||
| 93 | current_elm = current_elm.next.?; | ||
| 94 | } | ||
| 95 | current_elm.next = node.next; | ||
| 96 | } | ||
| 97 | } | ||
| 98 | |||
| 99 | /// Remove and return the first node in the list. | ||
| 100 | /// | ||
| 101 | /// Returns: | ||
| 102 | /// A pointer to the first node in the list. | ||
| 103 | pub fn popFirst(list: *Self) ?*Node { | ||
| 104 | const first = list.first orelse return null; | ||
| 105 | list.first = first.next; | ||
| 106 | return first; | ||
| 107 | } | ||
| 108 | |||
| 109 | /// Allocate a new node. | ||
| 110 | /// | ||
| 111 | /// Arguments: | ||
| 112 | /// allocator: Dynamic memory allocator. | ||
| 113 | /// | ||
| 114 | /// Returns: | ||
| 115 | /// A pointer to the new node. | ||
| 116 | pub fn allocateNode(list: *Self, allocator: *Allocator) !*Node { | ||
| 117 | return allocator.create(Node); | ||
| 118 | } | ||
| 119 | |||
| 120 | /// Deallocate a node. | ||
| 121 | /// | ||
| 122 | /// Arguments: | ||
| 123 | /// node: Pointer to the node to deallocate. | ||
| 124 | /// allocator: Dynamic memory allocator. | ||
| 125 | pub fn destroyNode(list: *Self, node: *Node, allocator: *Allocator) void { | ||
| 126 | allocator.destroy(node); | ||
| 127 | } | ||
| 128 | |||
| 129 | /// Allocate and initialize a node and its data. | ||
| 130 | /// | ||
| 131 | /// Arguments: | ||
| 132 | /// data: The data to put inside the node. | ||
| 133 | /// allocator: Dynamic memory allocator. | ||
| 134 | /// | ||
| 135 | /// Returns: | ||
| 136 | /// A pointer to the new node. | ||
| 137 | pub fn createNode(list: *Self, data: T, allocator: *Allocator) !*Node { | ||
| 138 | var node = try list.allocateNode(allocator); | ||
| 139 | node.* = Node.init(data); | ||
| 140 | return node; | ||
| 141 | } | ||
| 142 | }; | ||
| 143 | } | ||
| 144 | |||
| 145 | test "basic SinglyLinkedList test" { | ||
| 146 | const allocator = debug.global_allocator; | ||
| 147 | var list = SinglyLinkedList(u32).init(); | ||
| 148 | |||
| 149 | var one = try list.createNode(1, allocator); | ||
| 150 | var two = try list.createNode(2, allocator); | ||
| 151 | var three = try list.createNode(3, allocator); | ||
| 152 | var four = try list.createNode(4, allocator); | ||
| 153 | var five = try list.createNode(5, allocator); | ||
| 154 | defer { | ||
| 155 | list.destroyNode(one, allocator); | ||
| 156 | list.destroyNode(two, allocator); | ||
| 157 | list.destroyNode(three, allocator); | ||
| 158 | list.destroyNode(four, allocator); | ||
| 159 | list.destroyNode(five, allocator); | ||
| 160 | } | ||
| 161 | |||
| 162 | list.prepend(two); // {2} | ||
| 163 | list.insertAfter(two, five); // {2, 5} | ||
| 164 | list.prepend(one); // {1, 2, 5} | ||
| 165 | list.insertAfter(two, three); // {1, 2, 3, 5} | ||
| 166 | list.insertAfter(three, four); // {1, 2, 3, 4, 5} | ||
| 167 | |||
| 168 | // Traverse forwards. | ||
| 169 | { | ||
| 170 | var it = list.first; | ||
| 171 | var index: u32 = 1; | ||
| 172 | while (it) |node| : (it = node.next) { | ||
| 173 | testing.expect(node.data == index); | ||
| 174 | index += 1; | ||
| 175 | } | ||
| 176 | } | ||
| 177 | |||
| 178 | _ = list.popFirst(); // {2, 3, 4, 5} | ||
| 179 | _ = list.remove(five); // {2, 3, 4} | ||
| 180 | _ = two.removeNext(); // {2, 4} | ||
| 181 | |||
| 182 | testing.expect(list.first.?.data == 2); | ||
| 183 | testing.expect(list.first.?.next.?.data == 4); | ||
| 184 | testing.expect(list.first.?.next.?.next == null); | ||
| 185 | } | ||
| 186 | |||
| 187 | /// A tail queue is headed by a pair of pointers, one to the head of the | ||
| 188 | /// list and the other to the tail of the list. The elements are doubly | ||
| 189 | /// linked so that an arbitrary element can be removed without a need to | ||
| 190 | /// traverse the list. New elements can be added to the list before or | ||
| 191 | /// after an existing element, at the head of the list, or at the end of | ||
| 192 | /// the list. A tail queue may be traversed in either direction. | ||
| 193 | pub fn TailQueue(comptime T: type) type { | ||
| 10 | return struct { | 194 | return struct { |
| 11 | const Self = @This(); | 195 | const Self = @This(); |
| 12 | 196 | ||
| ... | @@ -219,9 +403,9 @@ pub fn LinkedList(comptime T: type) type { | ... | @@ -219,9 +403,9 @@ pub fn LinkedList(comptime T: type) type { |
| 219 | }; | 403 | }; |
| 220 | } | 404 | } |
| 221 | 405 | ||
| 222 | test "basic linked list test" { | 406 | test "basic TailQueue test" { |
| 223 | const allocator = debug.global_allocator; | 407 | const allocator = debug.global_allocator; |
| 224 | var list = LinkedList(u32).init(); | 408 | var list = TailQueue(u32).init(); |
| 225 | 409 | ||
| 226 | var one = try list.createNode(1, allocator); | 410 | var one = try list.createNode(1, allocator); |
| 227 | var two = try list.createNode(2, allocator); | 411 | var two = try list.createNode(2, allocator); |
| ... | @@ -271,10 +455,10 @@ test "basic linked list test" { | ... | @@ -271,10 +455,10 @@ test "basic linked list test" { |
| 271 | testing.expect(list.len == 2); | 455 | testing.expect(list.len == 2); |
| 272 | } | 456 | } |
| 273 | 457 | ||
| 274 | test "linked list concatenation" { | 458 | test "TailQueue concatenation" { |
| 275 | const allocator = debug.global_allocator; | 459 | const allocator = debug.global_allocator; |
| 276 | var list1 = LinkedList(u32).init(); | 460 | var list1 = TailQueue(u32).init(); |
| 277 | var list2 = LinkedList(u32).init(); | 461 | var list2 = TailQueue(u32).init(); |
| 278 | 462 | ||
| 279 | var one = try list1.createNode(1, allocator); | 463 | var one = try list1.createNode(1, allocator); |
| 280 | defer list1.destroyNode(one, allocator); | 464 | defer list1.destroyNode(one, allocator); |
std/std.zig+2-1| ... | @@ -7,17 +7,18 @@ pub const Buffer = @import("buffer.zig").Buffer; | ... | @@ -7,17 +7,18 @@ pub const Buffer = @import("buffer.zig").Buffer; |
| 7 | pub const BufferOutStream = @import("io.zig").BufferOutStream; | 7 | pub const BufferOutStream = @import("io.zig").BufferOutStream; |
| 8 | pub const DynLib = @import("dynamic_library.zig").DynLib; | 8 | pub const DynLib = @import("dynamic_library.zig").DynLib; |
| 9 | pub const HashMap = @import("hash_map.zig").HashMap; | 9 | pub const HashMap = @import("hash_map.zig").HashMap; |
| 10 | pub const LinkedList = @import("linked_list.zig").LinkedList; | ||
| 11 | pub const Mutex = @import("mutex.zig").Mutex; | 10 | pub const Mutex = @import("mutex.zig").Mutex; |
| 12 | pub const PackedIntArrayEndian = @import("packed_int_array.zig").PackedIntArrayEndian; | 11 | pub const PackedIntArrayEndian = @import("packed_int_array.zig").PackedIntArrayEndian; |
| 13 | pub const PackedIntArray = @import("packed_int_array.zig").PackedIntArray; | 12 | pub const PackedIntArray = @import("packed_int_array.zig").PackedIntArray; |
| 14 | pub const PackedIntSliceEndian = @import("packed_int_array.zig").PackedIntSliceEndian; | 13 | pub const PackedIntSliceEndian = @import("packed_int_array.zig").PackedIntSliceEndian; |
| 15 | pub const PackedIntSlice = @import("packed_int_array.zig").PackedIntSlice; | 14 | pub const PackedIntSlice = @import("packed_int_array.zig").PackedIntSlice; |
| 16 | pub const PriorityQueue = @import("priority_queue.zig").PriorityQueue; | 15 | pub const PriorityQueue = @import("priority_queue.zig").PriorityQueue; |
| 16 | pub const SinglyLinkedList = @import("linked_list.zig").SinglyLinkedList; | ||
| 17 | pub const StaticallyInitializedMutex = @import("statically_initialized_mutex.zig").StaticallyInitializedMutex; | 17 | pub const StaticallyInitializedMutex = @import("statically_initialized_mutex.zig").StaticallyInitializedMutex; |
| 18 | pub const SegmentedList = @import("segmented_list.zig").SegmentedList; | 18 | pub const SegmentedList = @import("segmented_list.zig").SegmentedList; |
| 19 | pub const SpinLock = @import("spinlock.zig").SpinLock; | 19 | pub const SpinLock = @import("spinlock.zig").SpinLock; |
| 20 | pub const ChildProcess = @import("child_process.zig").ChildProcess; | 20 | pub const ChildProcess = @import("child_process.zig").ChildProcess; |
| 21 | pub const TailQueue = @import("linked_list.zig").TailQueue; | ||
| 21 | pub const Thread = @import("thread.zig").Thread; | 22 | pub const Thread = @import("thread.zig").Thread; |
| 22 | 23 | ||
| 23 | pub const atomic = @import("atomic.zig"); | 24 | pub const atomic = @import("atomic.zig"); |