| author | |
| committer | |
| log | 3b77a845f9a5409d19a9e330b82eece8af4ac18f |
| tree | f19a742742aabef64c6ce3842b3a12b97de52161 |
| parent | 1639fcea43549853f1fded32aa1d711d21771e1c |
by making it always intrusive, we make it more broadly useful API, and
avoid binary bloat.3 files changed, 275 insertions(+), 288 deletions(-)
lib/std/DoublyLinkedList.zig created+274| ... | @@ -0,0 +1,274 @@ | ||
| 1 | //! A doubly-linked list has a pair of pointers to both the head and | ||
| 2 | //! tail of the list. List elements have pointers to both the previous | ||
| 3 | //! and next elements in the sequence. The list can be traversed both | ||
| 4 | //! forward and backward. Some operations that take linear O(n) time | ||
| 5 | //! with a singly-linked list can be done without traversal in constant | ||
| 6 | //! O(1) time with a doubly-linked list: | ||
| 7 | //! | ||
| 8 | //! * Removing an element. | ||
| 9 | //! * Inserting a new element before an existing element. | ||
| 10 | //! * Pushing or popping an element from the end of the list. | ||
| 11 | |||
| 12 | const std = @import("std.zig"); | ||
| 13 | const debug = std.debug; | ||
| 14 | const assert = debug.assert; | ||
| 15 | const testing = std.testing; | ||
| 16 | const DoublyLinkedList = @This(); | ||
| 17 | |||
| 18 | first: ?*Node = null, | ||
| 19 | last: ?*Node = null, | ||
| 20 | len: usize = 0, | ||
| 21 | |||
| 22 | /// This struct contains only the prev and next pointers and not any data | ||
| 23 | /// payload. The intended usage is to embed it intrusively into another data | ||
| 24 | /// structure and access the data with `@fieldParentPtr`. | ||
| 25 | pub const Node = struct { | ||
| 26 | prev: ?*Node = null, | ||
| 27 | next: ?*Node = null, | ||
| 28 | }; | ||
| 29 | |||
| 30 | pub fn insertAfter(list: *DoublyLinkedList, existing_node: *Node, new_node: *Node) void { | ||
| 31 | new_node.prev = existing_node; | ||
| 32 | if (existing_node.next) |next_node| { | ||
| 33 | // Intermediate node. | ||
| 34 | new_node.next = next_node; | ||
| 35 | next_node.prev = new_node; | ||
| 36 | } else { | ||
| 37 | // Last element of the list. | ||
| 38 | new_node.next = null; | ||
| 39 | list.last = new_node; | ||
| 40 | } | ||
| 41 | existing_node.next = new_node; | ||
| 42 | |||
| 43 | list.len += 1; | ||
| 44 | } | ||
| 45 | |||
| 46 | pub fn insertBefore(list: *DoublyLinkedList, existing_node: *Node, new_node: *Node) void { | ||
| 47 | new_node.next = existing_node; | ||
| 48 | if (existing_node.prev) |prev_node| { | ||
| 49 | // Intermediate node. | ||
| 50 | new_node.prev = prev_node; | ||
| 51 | prev_node.next = new_node; | ||
| 52 | } else { | ||
| 53 | // First element of the list. | ||
| 54 | new_node.prev = null; | ||
| 55 | list.first = new_node; | ||
| 56 | } | ||
| 57 | existing_node.prev = new_node; | ||
| 58 | |||
| 59 | list.len += 1; | ||
| 60 | } | ||
| 61 | |||
| 62 | /// Concatenate list2 onto the end of list1, removing all entries from the former. | ||
| 63 | /// | ||
| 64 | /// Arguments: | ||
| 65 | /// list1: the list to concatenate onto | ||
| 66 | /// list2: the list to be concatenated | ||
| 67 | pub fn concatByMoving(list1: *DoublyLinkedList, list2: *DoublyLinkedList) void { | ||
| 68 | const l2_first = list2.first orelse return; | ||
| 69 | if (list1.last) |l1_last| { | ||
| 70 | l1_last.next = list2.first; | ||
| 71 | l2_first.prev = list1.last; | ||
| 72 | list1.len += list2.len; | ||
| 73 | } else { | ||
| 74 | // list1 was empty | ||
| 75 | list1.first = list2.first; | ||
| 76 | list1.len = list2.len; | ||
| 77 | } | ||
| 78 | list1.last = list2.last; | ||
| 79 | list2.first = null; | ||
| 80 | list2.last = null; | ||
| 81 | list2.len = 0; | ||
| 82 | } | ||
| 83 | |||
| 84 | /// Insert a new node at the end of the list. | ||
| 85 | /// | ||
| 86 | /// Arguments: | ||
| 87 | /// new_node: Pointer to the new node to insert. | ||
| 88 | pub fn append(list: *DoublyLinkedList, new_node: *Node) void { | ||
| 89 | if (list.last) |last| { | ||
| 90 | // Insert after last. | ||
| 91 | list.insertAfter(last, new_node); | ||
| 92 | } else { | ||
| 93 | // Empty list. | ||
| 94 | list.prepend(new_node); | ||
| 95 | } | ||
| 96 | } | ||
| 97 | |||
| 98 | /// Insert a new node at the beginning of the list. | ||
| 99 | /// | ||
| 100 | /// Arguments: | ||
| 101 | /// new_node: Pointer to the new node to insert. | ||
| 102 | pub fn prepend(list: *DoublyLinkedList, new_node: *Node) void { | ||
| 103 | if (list.first) |first| { | ||
| 104 | // Insert before first. | ||
| 105 | list.insertBefore(first, new_node); | ||
| 106 | } else { | ||
| 107 | // Empty list. | ||
| 108 | list.first = new_node; | ||
| 109 | list.last = new_node; | ||
| 110 | new_node.prev = null; | ||
| 111 | new_node.next = null; | ||
| 112 | |||
| 113 | list.len = 1; | ||
| 114 | } | ||
| 115 | } | ||
| 116 | |||
| 117 | /// Remove a node from the list. | ||
| 118 | /// | ||
| 119 | /// Arguments: | ||
| 120 | /// node: Pointer to the node to be removed. | ||
| 121 | pub fn remove(list: *DoublyLinkedList, node: *Node) void { | ||
| 122 | if (node.prev) |prev_node| { | ||
| 123 | // Intermediate node. | ||
| 124 | prev_node.next = node.next; | ||
| 125 | } else { | ||
| 126 | // First element of the list. | ||
| 127 | list.first = node.next; | ||
| 128 | } | ||
| 129 | |||
| 130 | if (node.next) |next_node| { | ||
| 131 | // Intermediate node. | ||
| 132 | next_node.prev = node.prev; | ||
| 133 | } else { | ||
| 134 | // Last element of the list. | ||
| 135 | list.last = node.prev; | ||
| 136 | } | ||
| 137 | |||
| 138 | list.len -= 1; | ||
| 139 | assert(list.len == 0 or (list.first != null and list.last != null)); | ||
| 140 | } | ||
| 141 | |||
| 142 | /// Remove and return the last node in the list. | ||
| 143 | /// | ||
| 144 | /// Returns: | ||
| 145 | /// A pointer to the last node in the list. | ||
| 146 | pub fn pop(list: *DoublyLinkedList) ?*Node { | ||
| 147 | const last = list.last orelse return null; | ||
| 148 | list.remove(last); | ||
| 149 | return last; | ||
| 150 | } | ||
| 151 | |||
| 152 | /// Remove and return the first node in the list. | ||
| 153 | /// | ||
| 154 | /// Returns: | ||
| 155 | /// A pointer to the first node in the list. | ||
| 156 | pub fn popFirst(list: *DoublyLinkedList) ?*Node { | ||
| 157 | const first = list.first orelse return null; | ||
| 158 | list.remove(first); | ||
| 159 | return first; | ||
| 160 | } | ||
| 161 | |||
| 162 | test "basic DoublyLinkedList test" { | ||
| 163 | const L = DoublyLinkedList(u32); | ||
| 164 | var list = L{}; | ||
| 165 | |||
| 166 | var one = L.Node{ .data = 1 }; | ||
| 167 | var two = L.Node{ .data = 2 }; | ||
| 168 | var three = L.Node{ .data = 3 }; | ||
| 169 | var four = L.Node{ .data = 4 }; | ||
| 170 | var five = L.Node{ .data = 5 }; | ||
| 171 | |||
| 172 | list.append(&two); // {2} | ||
| 173 | list.append(&five); // {2, 5} | ||
| 174 | list.prepend(&one); // {1, 2, 5} | ||
| 175 | list.insertBefore(&five, &four); // {1, 2, 4, 5} | ||
| 176 | list.insertAfter(&two, &three); // {1, 2, 3, 4, 5} | ||
| 177 | |||
| 178 | // Traverse forwards. | ||
| 179 | { | ||
| 180 | var it = list.first; | ||
| 181 | var index: u32 = 1; | ||
| 182 | while (it) |node| : (it = node.next) { | ||
| 183 | try testing.expect(node.data == index); | ||
| 184 | index += 1; | ||
| 185 | } | ||
| 186 | } | ||
| 187 | |||
| 188 | // Traverse backwards. | ||
| 189 | { | ||
| 190 | var it = list.last; | ||
| 191 | var index: u32 = 1; | ||
| 192 | while (it) |node| : (it = node.prev) { | ||
| 193 | try testing.expect(node.data == (6 - index)); | ||
| 194 | index += 1; | ||
| 195 | } | ||
| 196 | } | ||
| 197 | |||
| 198 | _ = list.popFirst(); // {2, 3, 4, 5} | ||
| 199 | _ = list.pop(); // {2, 3, 4} | ||
| 200 | list.remove(&three); // {2, 4} | ||
| 201 | |||
| 202 | try testing.expect(list.first.?.data == 2); | ||
| 203 | try testing.expect(list.last.?.data == 4); | ||
| 204 | try testing.expect(list.len == 2); | ||
| 205 | } | ||
| 206 | |||
| 207 | test "DoublyLinkedList concatenation" { | ||
| 208 | const L = DoublyLinkedList(u32); | ||
| 209 | var list1 = L{}; | ||
| 210 | var list2 = L{}; | ||
| 211 | |||
| 212 | var one = L.Node{ .data = 1 }; | ||
| 213 | var two = L.Node{ .data = 2 }; | ||
| 214 | var three = L.Node{ .data = 3 }; | ||
| 215 | var four = L.Node{ .data = 4 }; | ||
| 216 | var five = L.Node{ .data = 5 }; | ||
| 217 | |||
| 218 | list1.append(&one); | ||
| 219 | list1.append(&two); | ||
| 220 | list2.append(&three); | ||
| 221 | list2.append(&four); | ||
| 222 | list2.append(&five); | ||
| 223 | |||
| 224 | list1.concatByMoving(&list2); | ||
| 225 | |||
| 226 | try testing.expect(list1.last == &five); | ||
| 227 | try testing.expect(list1.len == 5); | ||
| 228 | try testing.expect(list2.first == null); | ||
| 229 | try testing.expect(list2.last == null); | ||
| 230 | try testing.expect(list2.len == 0); | ||
| 231 | |||
| 232 | // Traverse forwards. | ||
| 233 | { | ||
| 234 | var it = list1.first; | ||
| 235 | var index: u32 = 1; | ||
| 236 | while (it) |node| : (it = node.next) { | ||
| 237 | try testing.expect(node.data == index); | ||
| 238 | index += 1; | ||
| 239 | } | ||
| 240 | } | ||
| 241 | |||
| 242 | // Traverse backwards. | ||
| 243 | { | ||
| 244 | var it = list1.last; | ||
| 245 | var index: u32 = 1; | ||
| 246 | while (it) |node| : (it = node.prev) { | ||
| 247 | try testing.expect(node.data == (6 - index)); | ||
| 248 | index += 1; | ||
| 249 | } | ||
| 250 | } | ||
| 251 | |||
| 252 | // Swap them back, this verifies that concatenating to an empty list works. | ||
| 253 | list2.concatByMoving(&list1); | ||
| 254 | |||
| 255 | // Traverse forwards. | ||
| 256 | { | ||
| 257 | var it = list2.first; | ||
| 258 | var index: u32 = 1; | ||
| 259 | while (it) |node| : (it = node.next) { | ||
| 260 | try testing.expect(node.data == index); | ||
| 261 | index += 1; | ||
| 262 | } | ||
| 263 | } | ||
| 264 | |||
| 265 | // Traverse backwards. | ||
| 266 | { | ||
| 267 | var it = list2.last; | ||
| 268 | var index: u32 = 1; | ||
| 269 | while (it) |node| : (it = node.prev) { | ||
| 270 | try testing.expect(node.data == (6 - index)); | ||
| 271 | index += 1; | ||
| 272 | } | ||
| 273 | } | ||
| 274 | } | ||
lib/std/linked_list.zig deleted-287| ... | @@ -1,287 +0,0 @@ | ||
| 1 | const std = @import("std.zig"); | ||
| 2 | const debug = std.debug; | ||
| 3 | const assert = debug.assert; | ||
| 4 | const testing = std.testing; | ||
| 5 | |||
| 6 | /// A doubly-linked list has a pair of pointers to both the head and | ||
| 7 | /// tail of the list. List elements have pointers to both the previous | ||
| 8 | /// and next elements in the sequence. The list can be traversed both | ||
| 9 | /// forward and backward. Some operations that take linear O(n) time | ||
| 10 | /// with a singly-linked list can be done without traversal in constant | ||
| 11 | /// O(1) time with a doubly-linked list: | ||
| 12 | /// | ||
| 13 | /// - Removing an element. | ||
| 14 | /// - Inserting a new element before an existing element. | ||
| 15 | /// - Pushing or popping an element from the end of the list. | ||
| 16 | pub fn DoublyLinkedList(comptime T: type) type { | ||
| 17 | return struct { | ||
| 18 | const Self = @This(); | ||
| 19 | |||
| 20 | /// Node inside the linked list wrapping the actual data. | ||
| 21 | pub const Node = struct { | ||
| 22 | prev: ?*Node = null, | ||
| 23 | next: ?*Node = null, | ||
| 24 | data: T, | ||
| 25 | }; | ||
| 26 | |||
| 27 | first: ?*Node = null, | ||
| 28 | last: ?*Node = null, | ||
| 29 | len: usize = 0, | ||
| 30 | |||
| 31 | /// Insert a new node after an existing one. | ||
| 32 | /// | ||
| 33 | /// Arguments: | ||
| 34 | /// node: Pointer to a node in the list. | ||
| 35 | /// new_node: Pointer to the new node to insert. | ||
| 36 | pub fn insertAfter(list: *Self, node: *Node, new_node: *Node) void { | ||
| 37 | new_node.prev = node; | ||
| 38 | if (node.next) |next_node| { | ||
| 39 | // Intermediate node. | ||
| 40 | new_node.next = next_node; | ||
| 41 | next_node.prev = new_node; | ||
| 42 | } else { | ||
| 43 | // Last element of the list. | ||
| 44 | new_node.next = null; | ||
| 45 | list.last = new_node; | ||
| 46 | } | ||
| 47 | node.next = new_node; | ||
| 48 | |||
| 49 | list.len += 1; | ||
| 50 | } | ||
| 51 | |||
| 52 | /// Insert a new node before an existing one. | ||
| 53 | /// | ||
| 54 | /// Arguments: | ||
| 55 | /// node: Pointer to a node in the list. | ||
| 56 | /// new_node: Pointer to the new node to insert. | ||
| 57 | pub fn insertBefore(list: *Self, node: *Node, new_node: *Node) void { | ||
| 58 | new_node.next = node; | ||
| 59 | if (node.prev) |prev_node| { | ||
| 60 | // Intermediate node. | ||
| 61 | new_node.prev = prev_node; | ||
| 62 | prev_node.next = new_node; | ||
| 63 | } else { | ||
| 64 | // First element of the list. | ||
| 65 | new_node.prev = null; | ||
| 66 | list.first = new_node; | ||
| 67 | } | ||
| 68 | node.prev = new_node; | ||
| 69 | |||
| 70 | list.len += 1; | ||
| 71 | } | ||
| 72 | |||
| 73 | /// Concatenate list2 onto the end of list1, removing all entries from the former. | ||
| 74 | /// | ||
| 75 | /// Arguments: | ||
| 76 | /// list1: the list to concatenate onto | ||
| 77 | /// list2: the list to be concatenated | ||
| 78 | pub fn concatByMoving(list1: *Self, list2: *Self) void { | ||
| 79 | const l2_first = list2.first orelse return; | ||
| 80 | if (list1.last) |l1_last| { | ||
| 81 | l1_last.next = list2.first; | ||
| 82 | l2_first.prev = list1.last; | ||
| 83 | list1.len += list2.len; | ||
| 84 | } else { | ||
| 85 | // list1 was empty | ||
| 86 | list1.first = list2.first; | ||
| 87 | list1.len = list2.len; | ||
| 88 | } | ||
| 89 | list1.last = list2.last; | ||
| 90 | list2.first = null; | ||
| 91 | list2.last = null; | ||
| 92 | list2.len = 0; | ||
| 93 | } | ||
| 94 | |||
| 95 | /// Insert a new node at the end of the list. | ||
| 96 | /// | ||
| 97 | /// Arguments: | ||
| 98 | /// new_node: Pointer to the new node to insert. | ||
| 99 | pub fn append(list: *Self, new_node: *Node) void { | ||
| 100 | if (list.last) |last| { | ||
| 101 | // Insert after last. | ||
| 102 | list.insertAfter(last, new_node); | ||
| 103 | } else { | ||
| 104 | // Empty list. | ||
| 105 | list.prepend(new_node); | ||
| 106 | } | ||
| 107 | } | ||
| 108 | |||
| 109 | /// Insert a new node at the beginning of the list. | ||
| 110 | /// | ||
| 111 | /// Arguments: | ||
| 112 | /// new_node: Pointer to the new node to insert. | ||
| 113 | pub fn prepend(list: *Self, new_node: *Node) void { | ||
| 114 | if (list.first) |first| { | ||
| 115 | // Insert before first. | ||
| 116 | list.insertBefore(first, new_node); | ||
| 117 | } else { | ||
| 118 | // Empty list. | ||
| 119 | list.first = new_node; | ||
| 120 | list.last = new_node; | ||
| 121 | new_node.prev = null; | ||
| 122 | new_node.next = null; | ||
| 123 | |||
| 124 | list.len = 1; | ||
| 125 | } | ||
| 126 | } | ||
| 127 | |||
| 128 | /// Remove a node from the list. | ||
| 129 | /// | ||
| 130 | /// Arguments: | ||
| 131 | /// node: Pointer to the node to be removed. | ||
| 132 | pub fn remove(list: *Self, node: *Node) void { | ||
| 133 | if (node.prev) |prev_node| { | ||
| 134 | // Intermediate node. | ||
| 135 | prev_node.next = node.next; | ||
| 136 | } else { | ||
| 137 | // First element of the list. | ||
| 138 | list.first = node.next; | ||
| 139 | } | ||
| 140 | |||
| 141 | if (node.next) |next_node| { | ||
| 142 | // Intermediate node. | ||
| 143 | next_node.prev = node.prev; | ||
| 144 | } else { | ||
| 145 | // Last element of the list. | ||
| 146 | list.last = node.prev; | ||
| 147 | } | ||
| 148 | |||
| 149 | list.len -= 1; | ||
| 150 | assert(list.len == 0 or (list.first != null and list.last != null)); | ||
| 151 | } | ||
| 152 | |||
| 153 | /// Remove and return the last node in the list. | ||
| 154 | /// | ||
| 155 | /// Returns: | ||
| 156 | /// A pointer to the last node in the list. | ||
| 157 | pub fn pop(list: *Self) ?*Node { | ||
| 158 | const last = list.last orelse return null; | ||
| 159 | list.remove(last); | ||
| 160 | return last; | ||
| 161 | } | ||
| 162 | |||
| 163 | /// Remove and return the first node in the list. | ||
| 164 | /// | ||
| 165 | /// Returns: | ||
| 166 | /// A pointer to the first node in the list. | ||
| 167 | pub fn popFirst(list: *Self) ?*Node { | ||
| 168 | const first = list.first orelse return null; | ||
| 169 | list.remove(first); | ||
| 170 | return first; | ||
| 171 | } | ||
| 172 | }; | ||
| 173 | } | ||
| 174 | |||
| 175 | test "basic DoublyLinkedList test" { | ||
| 176 | const L = DoublyLinkedList(u32); | ||
| 177 | var list = L{}; | ||
| 178 | |||
| 179 | var one = L.Node{ .data = 1 }; | ||
| 180 | var two = L.Node{ .data = 2 }; | ||
| 181 | var three = L.Node{ .data = 3 }; | ||
| 182 | var four = L.Node{ .data = 4 }; | ||
| 183 | var five = L.Node{ .data = 5 }; | ||
| 184 | |||
| 185 | list.append(&two); // {2} | ||
| 186 | list.append(&five); // {2, 5} | ||
| 187 | list.prepend(&one); // {1, 2, 5} | ||
| 188 | list.insertBefore(&five, &four); // {1, 2, 4, 5} | ||
| 189 | list.insertAfter(&two, &three); // {1, 2, 3, 4, 5} | ||
| 190 | |||
| 191 | // Traverse forwards. | ||
| 192 | { | ||
| 193 | var it = list.first; | ||
| 194 | var index: u32 = 1; | ||
| 195 | while (it) |node| : (it = node.next) { | ||
| 196 | try testing.expect(node.data == index); | ||
| 197 | index += 1; | ||
| 198 | } | ||
| 199 | } | ||
| 200 | |||
| 201 | // Traverse backwards. | ||
| 202 | { | ||
| 203 | var it = list.last; | ||
| 204 | var index: u32 = 1; | ||
| 205 | while (it) |node| : (it = node.prev) { | ||
| 206 | try testing.expect(node.data == (6 - index)); | ||
| 207 | index += 1; | ||
| 208 | } | ||
| 209 | } | ||
| 210 | |||
| 211 | _ = list.popFirst(); // {2, 3, 4, 5} | ||
| 212 | _ = list.pop(); // {2, 3, 4} | ||
| 213 | list.remove(&three); // {2, 4} | ||
| 214 | |||
| 215 | try testing.expect(list.first.?.data == 2); | ||
| 216 | try testing.expect(list.last.?.data == 4); | ||
| 217 | try testing.expect(list.len == 2); | ||
| 218 | } | ||
| 219 | |||
| 220 | test "DoublyLinkedList concatenation" { | ||
| 221 | const L = DoublyLinkedList(u32); | ||
| 222 | var list1 = L{}; | ||
| 223 | var list2 = L{}; | ||
| 224 | |||
| 225 | var one = L.Node{ .data = 1 }; | ||
| 226 | var two = L.Node{ .data = 2 }; | ||
| 227 | var three = L.Node{ .data = 3 }; | ||
| 228 | var four = L.Node{ .data = 4 }; | ||
| 229 | var five = L.Node{ .data = 5 }; | ||
| 230 | |||
| 231 | list1.append(&one); | ||
| 232 | list1.append(&two); | ||
| 233 | list2.append(&three); | ||
| 234 | list2.append(&four); | ||
| 235 | list2.append(&five); | ||
| 236 | |||
| 237 | list1.concatByMoving(&list2); | ||
| 238 | |||
| 239 | try testing.expect(list1.last == &five); | ||
| 240 | try testing.expect(list1.len == 5); | ||
| 241 | try testing.expect(list2.first == null); | ||
| 242 | try testing.expect(list2.last == null); | ||
| 243 | try testing.expect(list2.len == 0); | ||
| 244 | |||
| 245 | // Traverse forwards. | ||
| 246 | { | ||
| 247 | var it = list1.first; | ||
| 248 | var index: u32 = 1; | ||
| 249 | while (it) |node| : (it = node.next) { | ||
| 250 | try testing.expect(node.data == index); | ||
| 251 | index += 1; | ||
| 252 | } | ||
| 253 | } | ||
| 254 | |||
| 255 | // Traverse backwards. | ||
| 256 | { | ||
| 257 | var it = list1.last; | ||
| 258 | var index: u32 = 1; | ||
| 259 | while (it) |node| : (it = node.prev) { | ||
| 260 | try testing.expect(node.data == (6 - index)); | ||
| 261 | index += 1; | ||
| 262 | } | ||
| 263 | } | ||
| 264 | |||
| 265 | // Swap them back, this verifies that concatenating to an empty list works. | ||
| 266 | list2.concatByMoving(&list1); | ||
| 267 | |||
| 268 | // Traverse forwards. | ||
| 269 | { | ||
| 270 | var it = list2.first; | ||
| 271 | var index: u32 = 1; | ||
| 272 | while (it) |node| : (it = node.next) { | ||
| 273 | try testing.expect(node.data == index); | ||
| 274 | index += 1; | ||
| 275 | } | ||
| 276 | } | ||
| 277 | |||
| 278 | // Traverse backwards. | ||
| 279 | { | ||
| 280 | var it = list2.last; | ||
| 281 | var index: u32 = 1; | ||
| 282 | while (it) |node| : (it = node.prev) { | ||
| 283 | try testing.expect(node.data == (6 - index)); | ||
| 284 | index += 1; | ||
| 285 | } | ||
| 286 | } | ||
| 287 | } | ||
lib/std/std.zig+1-1| ... | @@ -16,7 +16,7 @@ pub const BufMap = @import("buf_map.zig").BufMap; | ... | @@ -16,7 +16,7 @@ pub const BufMap = @import("buf_map.zig").BufMap; |
| 16 | pub const BufSet = @import("buf_set.zig").BufSet; | 16 | pub const BufSet = @import("buf_set.zig").BufSet; |
| 17 | pub const StaticStringMap = static_string_map.StaticStringMap; | 17 | pub const StaticStringMap = static_string_map.StaticStringMap; |
| 18 | pub const StaticStringMapWithEql = static_string_map.StaticStringMapWithEql; | 18 | pub const StaticStringMapWithEql = static_string_map.StaticStringMapWithEql; |
| 19 | pub const DoublyLinkedList = @import("linked_list.zig").DoublyLinkedList; | 19 | pub const DoublyLinkedList = @import("DoublyLinkedList.zig"); |
| 20 | pub const DynLib = @import("dynamic_library.zig").DynLib; | 20 | pub const DynLib = @import("dynamic_library.zig").DynLib; |
| 21 | pub const DynamicBitSet = bit_set.DynamicBitSet; | 21 | pub const DynamicBitSet = bit_set.DynamicBitSet; |
| 22 | pub const DynamicBitSetUnmanaged = bit_set.DynamicBitSetUnmanaged; | 22 | pub const DynamicBitSetUnmanaged = bit_set.DynamicBitSetUnmanaged; |