| ... | ... | @@ -82,6 +82,28 @@ pub fn LinkedList(comptime T: type) type { |
| 82 | 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 | 107 | /// Insert a new node at the end of the list. |
| 86 | 108 | /// |
| 87 | 109 | /// Arguments: |
| ... | ... | @@ -247,3 +269,77 @@ test "basic linked list test" { |
| 247 | 269 | assert(list.last.?.data == 4); |
| 248 | 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 | } |