| ... | @@ -82,6 +82,28 @@ pub fn LinkedList(comptime T: type) type { | ... | @@ -82,6 +82,28 @@ pub fn LinkedList(comptime T: type) type { |
| 82 | list.len += 1; | 82 | list.len += 1; |
| 83 | } | 83 | } |
| 84 | | 84 | |
| | 85 | /// Concatenate list2 onto the end of list1, removing all entries from the former. |
| | 86 | /// |
| | 87 | /// Arguments: |
| | 88 | /// list1: the list to concatenate onto |
| | 89 | /// list2: the list to be concatenated |
| | 90 | pub fn concatByMoving(list1: *Self, list2: *Self) void { |
| | 91 | const l2_first = list2.first orelse return; |
| | 92 | if (list1.last) |l1_last| { |
| | 93 | l1_last.next = list2.first; |
| | 94 | l2_first.prev = list1.last; |
| | 95 | list1.len += list2.len; |
| | 96 | } else { |
| | 97 | // list1 was empty |
| | 98 | list1.first = list2.first; |
| | 99 | list1.len = list2.len; |
| | 100 | } |
| | 101 | list1.last = list2.last; |
| | 102 | list2.first = null; |
| | 103 | list2.last = null; |
| | 104 | list2.len = 0; |
| | 105 | } |
| | 106 | |
| 85 | /// Insert a new node at the end of the list. | 107 | /// Insert a new node at the end of the list. |
| 86 | /// | 108 | /// |
| 87 | /// Arguments: | 109 | /// Arguments: |
| ... | @@ -247,3 +269,77 @@ test "basic linked list test" { | ... | @@ -247,3 +269,77 @@ test "basic linked list test" { |
| 247 | assert(list.last.?.data == 4); | 269 | assert(list.last.?.data == 4); |
| 248 | assert(list.len == 2); | 270 | assert(list.len == 2); |
| 249 | } | 271 | } |
| | 272 | |
| | 273 | test "linked list concatenation" { |
| | 274 | const allocator = debug.global_allocator; |
| | 275 | var list1 = LinkedList(u32).init(); |
| | 276 | var list2 = LinkedList(u32).init(); |
| | 277 | |
| | 278 | var one = try list1.createNode(1, allocator); |
| | 279 | defer list1.destroyNode(one, allocator); |
| | 280 | var two = try list1.createNode(2, allocator); |
| | 281 | defer list1.destroyNode(two, allocator); |
| | 282 | var three = try list1.createNode(3, allocator); |
| | 283 | defer list1.destroyNode(three, allocator); |
| | 284 | var four = try list1.createNode(4, allocator); |
| | 285 | defer list1.destroyNode(four, allocator); |
| | 286 | var five = try list1.createNode(5, allocator); |
| | 287 | defer list1.destroyNode(five, allocator); |
| | 288 | |
| | 289 | list1.append(one); |
| | 290 | list1.append(two); |
| | 291 | list2.append(three); |
| | 292 | list2.append(four); |
| | 293 | list2.append(five); |
| | 294 | |
| | 295 | list1.concatByMoving(&list2); |
| | 296 | |
| | 297 | assert(list1.last == five); |
| | 298 | assert(list1.len == 5); |
| | 299 | assert(list2.first == null); |
| | 300 | assert(list2.last == null); |
| | 301 | assert(list2.len == 0); |
| | 302 | |
| | 303 | // Traverse forwards. |
| | 304 | { |
| | 305 | var it = list1.first; |
| | 306 | var index: u32 = 1; |
| | 307 | while (it) |node| : (it = node.next) { |
| | 308 | assert(node.data == index); |
| | 309 | index += 1; |
| | 310 | } |
| | 311 | } |
| | 312 | |
| | 313 | // Traverse backwards. |
| | 314 | { |
| | 315 | var it = list1.last; |
| | 316 | var index: u32 = 1; |
| | 317 | while (it) |node| : (it = node.prev) { |
| | 318 | assert(node.data == (6 - index)); |
| | 319 | index += 1; |
| | 320 | } |
| | 321 | } |
| | 322 | |
| | 323 | // Swap them back, this verifies that concating to an empty list works. |
| | 324 | list2.concatByMoving(&list1); |
| | 325 | |
| | 326 | // Traverse forwards. |
| | 327 | { |
| | 328 | var it = list2.first; |
| | 329 | var index: u32 = 1; |
| | 330 | while (it) |node| : (it = node.next) { |
| | 331 | assert(node.data == index); |
| | 332 | index += 1; |
| | 333 | } |
| | 334 | } |
| | 335 | |
| | 336 | // Traverse backwards. |
| | 337 | { |
| | 338 | var it = list2.last; |
| | 339 | var index: u32 = 1; |
| | 340 | while (it) |node| : (it = node.prev) { |
| | 341 | assert(node.data == (6 - index)); |
| | 342 | index += 1; |
| | 343 | } |
| | 344 | } |
| | 345 | } |