| 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 | 160 | /// it uses an optional pointer so that tombstone removals are possible |
| 161 | 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 | 165 | windows_subsystem_windows: bool, |
| 166 | 166 | windows_subsystem_console: bool, |
src-self-hosted/value.zig+1-1| ... | ... | @@ -186,7 +186,7 @@ pub const Value = struct { |
| 186 | 186 | /// Path to the object file that contains this function |
| 187 | 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 | 191 | /// Creates a Fn value with 1 ref |
| 192 | 192 | /// Takes ownership of symbol_name |
std/atomic/queue.zig+1-1| ... | ... | @@ -14,7 +14,7 @@ pub fn Queue(comptime T: type) type { |
| 14 | 14 | mutex: std.Mutex, |
| 15 | 15 | |
| 16 | 16 | pub const Self = @This(); |
| 17 | pub const Node = std.LinkedList(T).Node; | |
| 17 | pub const Node = std.TailQueue(T).Node; | |
| 18 | 18 | |
| 19 | 19 | pub fn init() Self { |
| 20 | 20 | return Self{ |
std/child_process.zig+3-3| ... | ... | @@ -13,7 +13,7 @@ const BufMap = std.BufMap; |
| 13 | 13 | const Buffer = std.Buffer; |
| 14 | 14 | const builtin = @import("builtin"); |
| 15 | 15 | const Os = builtin.Os; |
| 16 | const LinkedList = std.LinkedList; | |
| 16 | const TailQueue = std.TailQueue; | |
| 17 | 17 | const maxInt = std.math.maxInt; |
| 18 | 18 | |
| 19 | 19 | pub const ChildProcess = struct { |
| ... | ... | @@ -48,7 +48,7 @@ pub const ChildProcess = struct { |
| 48 | 48 | pub cwd: ?[]const u8, |
| 49 | 49 | |
| 50 | 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 | 53 | pub const SpawnError = error{OutOfMemory} || os.ExecveError || os.SetIdError || |
| 54 | 54 | os.ChangeCurDirError || windows.CreateProcessError; |
| ... | ... | @@ -388,7 +388,7 @@ pub const ChildProcess = struct { |
| 388 | 388 | |
| 389 | 389 | self.pid = pid; |
| 390 | 390 | self.err_pipe = err_pipe; |
| 391 | self.llnode = LinkedList(*ChildProcess).Node.init(self); | |
| 391 | self.llnode = TailQueue(*ChildProcess).Node.init(self); | |
| 392 | 392 | self.term = null; |
| 393 | 393 | |
| 394 | 394 | if (self.stdin_behavior == StdIo.Pipe) { |
std/event/net.zig+1-1| ... | ... | @@ -19,7 +19,7 @@ pub const Server = struct { |
| 19 | 19 | waiting_for_emfile_node: PromiseNode, |
| 20 | 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 | 24 | pub fn init(loop: *Loop) Server { |
| 25 | 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 | 347 | pub allocator: Allocator, |
| 348 | 348 | |
| 349 | 349 | child_allocator: *Allocator, |
| 350 | buffer_list: std.LinkedList([]u8), | |
| 350 | buffer_list: std.SinglyLinkedList([]u8), | |
| 351 | 351 | end_index: usize, |
| 352 | 352 | |
| 353 | const BufNode = std.LinkedList([]u8).Node; | |
| 353 | const BufNode = std.SinglyLinkedList([]u8).Node; | |
| 354 | 354 | |
| 355 | 355 | pub fn init(child_allocator: *Allocator) ArenaAllocator { |
| 356 | 356 | return ArenaAllocator{ |
| ... | ... | @@ -359,7 +359,7 @@ pub const ArenaAllocator = struct { |
| 359 | 359 | .shrinkFn = shrink, |
| 360 | 360 | }, |
| 361 | 361 | .child_allocator = child_allocator, |
| 362 | .buffer_list = std.LinkedList([]u8).init(), | |
| 362 | .buffer_list = std.SinglyLinkedList([]u8).init(), | |
| 363 | 363 | .end_index = 0, |
| 364 | 364 | }; |
| 365 | 365 | } |
| ... | ... | @@ -387,10 +387,9 @@ pub const ArenaAllocator = struct { |
| 387 | 387 | const buf_node = &buf_node_slice[0]; |
| 388 | 388 | buf_node.* = BufNode{ |
| 389 | 389 | .data = buf, |
| 390 | .prev = null, | |
| 391 | 390 | .next = null, |
| 392 | 391 | }; |
| 393 | self.buffer_list.append(buf_node); | |
| 392 | self.buffer_list.prepend(buf_node); | |
| 394 | 393 | self.end_index = 0; |
| 395 | 394 | return buf_node; |
| 396 | 395 | } |
| ... | ... | @@ -398,7 +397,7 @@ pub const ArenaAllocator = struct { |
| 398 | 397 | fn alloc(allocator: *Allocator, n: usize, alignment: u29) ![]u8 { |
| 399 | 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 | 401 | while (true) { |
| 403 | 402 | const cur_buf = cur_node.data[@sizeOf(BufNode)..]; |
| 404 | 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 | 5 | const mem = std.mem; |
| 6 | 6 | const Allocator = mem.Allocator; |
| 7 | 7 | |
| 8 | /// Generic doubly linked list. | |
| 9 | pub fn LinkedList(comptime T: type) type { | |
| 8 | /// A singly-linked list is headed by a single forward pointer. The elements | |
| 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 | 194 | return struct { |
| 11 | 195 | const Self = @This(); |
| 12 | 196 | |
| ... | ... | @@ -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 | 407 | const allocator = debug.global_allocator; |
| 224 | var list = LinkedList(u32).init(); | |
| 408 | var list = TailQueue(u32).init(); | |
| 225 | 409 | |
| 226 | 410 | var one = try list.createNode(1, allocator); |
| 227 | 411 | var two = try list.createNode(2, allocator); |
| ... | ... | @@ -271,10 +455,10 @@ test "basic linked list test" { |
| 271 | 455 | testing.expect(list.len == 2); |
| 272 | 456 | } |
| 273 | 457 | |
| 274 | test "linked list concatenation" { | |
| 458 | test "TailQueue concatenation" { | |
| 275 | 459 | const allocator = debug.global_allocator; |
| 276 | var list1 = LinkedList(u32).init(); | |
| 277 | var list2 = LinkedList(u32).init(); | |
| 460 | var list1 = TailQueue(u32).init(); | |
| 461 | var list2 = TailQueue(u32).init(); | |
| 278 | 462 | |
| 279 | 463 | var one = try list1.createNode(1, allocator); |
| 280 | 464 | defer list1.destroyNode(one, allocator); |
std/std.zig+2-1| ... | ... | @@ -7,17 +7,18 @@ pub const Buffer = @import("buffer.zig").Buffer; |
| 7 | 7 | pub const BufferOutStream = @import("io.zig").BufferOutStream; |
| 8 | 8 | pub const DynLib = @import("dynamic_library.zig").DynLib; |
| 9 | 9 | pub const HashMap = @import("hash_map.zig").HashMap; |
| 10 | pub const LinkedList = @import("linked_list.zig").LinkedList; | |
| 11 | 10 | pub const Mutex = @import("mutex.zig").Mutex; |
| 12 | 11 | pub const PackedIntArrayEndian = @import("packed_int_array.zig").PackedIntArrayEndian; |
| 13 | 12 | pub const PackedIntArray = @import("packed_int_array.zig").PackedIntArray; |
| 14 | 13 | pub const PackedIntSliceEndian = @import("packed_int_array.zig").PackedIntSliceEndian; |
| 15 | 14 | pub const PackedIntSlice = @import("packed_int_array.zig").PackedIntSlice; |
| 16 | 15 | pub const PriorityQueue = @import("priority_queue.zig").PriorityQueue; |
| 16 | pub const SinglyLinkedList = @import("linked_list.zig").SinglyLinkedList; | |
| 17 | 17 | pub const StaticallyInitializedMutex = @import("statically_initialized_mutex.zig").StaticallyInitializedMutex; |
| 18 | 18 | pub const SegmentedList = @import("segmented_list.zig").SegmentedList; |
| 19 | 19 | pub const SpinLock = @import("spinlock.zig").SpinLock; |
| 20 | 20 | pub const ChildProcess = @import("child_process.zig").ChildProcess; |
| 21 | pub const TailQueue = @import("linked_list.zig").TailQueue; | |
| 21 | 22 | pub const Thread = @import("thread.zig").Thread; |
| 22 | 23 | |
| 23 | 24 | pub const atomic = @import("atomic.zig"); |