| ... | ... | @@ -29,6 +29,14 @@ pub fn MultiArrayList(comptime T: type) type { |
| 29 | 29 | .capacity = 0, |
| 30 | 30 | }; |
| 31 | 31 | |
| 32 | /// Initialize with capacity to hold exactly `num` elements. |
| 33 | /// Deinitialize with `deinit` or `toOwnedSlice`. |
| 34 | pub fn initCapacity(gpa: Allocator, num: usize) Allocator.Error!Self { |
| 35 | var self: Self = .empty; |
| 36 | try self.setCapacity(gpa, num); |
| 37 | return self; |
| 38 | } |
| 39 | |
| 32 | 40 | const Elem = switch (@typeInfo(T)) { |
| 33 | 41 | .@"struct" => T, |
| 34 | 42 | .@"union" => |u| struct { |
| ... | ... | @@ -253,31 +261,45 @@ pub fn MultiArrayList(comptime T: type) type { |
| 253 | 261 | return self.slice().get(index); |
| 254 | 262 | } |
| 255 | 263 | |
| 256 | | /// Extend the list by 1 element. Allocates more memory as necessary. |
| 257 | | pub fn append(self: *Self, gpa: Allocator, elem: T) !void { |
| 264 | /// Extend the list by 1 element. |
| 265 | /// |
| 266 | /// Allocates more memory as necessary. |
| 267 | pub fn append(self: *Self, gpa: Allocator, elem: T) Allocator.Error!void { |
| 258 | 268 | try self.ensureUnusedCapacity(gpa, 1); |
| 259 | 269 | self.appendAssumeCapacity(elem); |
| 260 | 270 | } |
| 261 | 271 | |
| 262 | | /// Extend the list by 1 element, but asserting `self.capacity` |
| 263 | | /// is sufficient to hold an additional item. |
| 272 | /// Extend the list by 1 element. |
| 273 | /// |
| 274 | /// Asserts that capacity is sufficient to hold an additional item. |
| 264 | 275 | pub fn appendAssumeCapacity(self: *Self, elem: T) void { |
| 265 | 276 | assert(self.len < self.capacity); |
| 266 | 277 | self.len += 1; |
| 267 | 278 | self.set(self.len - 1, elem); |
| 268 | 279 | } |
| 269 | 280 | |
| 281 | /// Extend the list by 1 element. |
| 282 | /// |
| 283 | /// If capacity is not sufficient to hold an additional |
| 284 | /// item, returns `error.OutOfMemory`. |
| 285 | pub fn appendBounded(self: *Self, elem: T) error{OutOfMemory}!void { |
| 286 | if (self.capacity - self.len < 1) return error.OutOfMemory; |
| 287 | return appendAssumeCapacity(self, elem); |
| 288 | } |
| 289 | |
| 270 | 290 | /// Extend the list by 1 element, returning the newly reserved |
| 271 | 291 | /// index with uninitialized data. |
| 272 | | /// Allocates more memory as necesasry. |
| 292 | /// |
| 293 | /// Allocates more memory as necessary. |
| 273 | 294 | pub fn addOne(self: *Self, gpa: Allocator) Allocator.Error!usize { |
| 274 | 295 | try self.ensureUnusedCapacity(gpa, 1); |
| 275 | 296 | return self.addOneAssumeCapacity(); |
| 276 | 297 | } |
| 277 | 298 | |
| 278 | | /// Extend the list by 1 element, asserting `self.capacity` |
| 279 | | /// is sufficient to hold an additional item. Returns the |
| 280 | | /// newly reserved index with uninitialized data. |
| 299 | /// Extend the list by 1 element, returning the newly reserved |
| 300 | /// index with uninitialized data. |
| 301 | /// |
| 302 | /// Asserts that capacity is sufficient to hold an additional item. |
| 281 | 303 | pub fn addOneAssumeCapacity(self: *Self) usize { |
| 282 | 304 | assert(self.len < self.capacity); |
| 283 | 305 | const index = self.len; |
| ... | ... | @@ -285,6 +307,16 @@ pub fn MultiArrayList(comptime T: type) type { |
| 285 | 307 | return index; |
| 286 | 308 | } |
| 287 | 309 | |
| 310 | /// Extend the list by 1 element, returning the newly reserved |
| 311 | /// index with uninitialized data. |
| 312 | /// |
| 313 | /// If capacity is not sufficient to hold an additional |
| 314 | /// item, returns `error.OutOfMemory`. |
| 315 | pub fn addOneBounded(self: *Self) error{OutOfMemory}!usize { |
| 316 | if (self.capacity - self.len < 1) return error.OutOfMemory; |
| 317 | return addOneAssumeCapacity(self); |
| 318 | } |
| 319 | |
| 288 | 320 | /// Remove and return the last element from the list, or return `null` if list is empty. |
| 289 | 321 | /// Invalidates pointers to fields of the removed element. |
| 290 | 322 | pub fn pop(self: *Self) ?T { |
| ... | ... | @@ -294,19 +326,21 @@ pub fn MultiArrayList(comptime T: type) type { |
| 294 | 326 | return val; |
| 295 | 327 | } |
| 296 | 328 | |
| 297 | | /// Inserts an item into an ordered list. Shifts all elements |
| 329 | /// Inserts an item into the list. Shifts all elements |
| 298 | 330 | /// after and including the specified index back by one and |
| 299 | | /// sets the given index to the specified element. May reallocate |
| 300 | | /// and invalidate iterators. |
| 331 | /// sets the given index to the specified element. |
| 332 | /// |
| 333 | /// Allocates more memory as necessary. |
| 301 | 334 | pub fn insert(self: *Self, gpa: Allocator, index: usize, elem: T) !void { |
| 302 | 335 | try self.ensureUnusedCapacity(gpa, 1); |
| 303 | 336 | self.insertAssumeCapacity(index, elem); |
| 304 | 337 | } |
| 305 | 338 | |
| 306 | | /// Inserts an item into an ordered list which has room for it. |
| 307 | | /// Shifts all elements after and including the specified index |
| 308 | | /// back by one and sets the given index to the specified element. |
| 309 | | /// Will not reallocate the array, does not invalidate iterators. |
| 339 | /// Inserts an item into the list. Shifts all elements |
| 340 | /// after and including the specified index back by one and |
| 341 | /// sets the given index to the specified element. |
| 342 | /// |
| 343 | /// Asserts that capacity is sufficient to hold an additional item. |
| 310 | 344 | pub fn insertAssumeCapacity(self: *Self, index: usize, elem: T) void { |
| 311 | 345 | assert(self.len < self.capacity); |
| 312 | 346 | assert(index <= self.len); |
| ... | ... | @@ -327,8 +361,19 @@ pub fn MultiArrayList(comptime T: type) type { |
| 327 | 361 | } |
| 328 | 362 | } |
| 329 | 363 | |
| 364 | /// Inserts an item into the list. Shifts all elements |
| 365 | /// after and including the specified index back by one and |
| 366 | /// sets the given index to the specified element. |
| 367 | /// |
| 368 | /// If capacity is not sufficient to hold an additional |
| 369 | /// item, returns `error.OutOfMemory`. |
| 370 | pub fn insertBounded(self: *Self, index: usize, elem: T) error{OutOfMemory}!void { |
| 371 | if (self.capacity - self.len < 1) return error.OutOfMemory; |
| 372 | return insertAssumeCapacity(self, index, elem); |
| 373 | } |
| 374 | |
| 330 | 375 | /// Remove the specified item from the list, swapping the last |
| 331 | | /// item in the list into its position. Fast, but does not |
| 376 | /// item in the list into its position. Fast, but does not |
| 332 | 377 | /// retain list ordering. |
| 333 | 378 | pub fn swapRemove(self: *Self, index: usize) void { |
| 334 | 379 | const slices = self.slice(); |
| ... | ... | @@ -393,7 +438,7 @@ pub fn MultiArrayList(comptime T: type) type { |
| 393 | 438 | |
| 394 | 439 | /// Adjust the list's length to `new_len`. |
| 395 | 440 | /// Does not initialize added items, if any. |
| 396 | | pub fn resize(self: *Self, gpa: Allocator, new_len: usize) !void { |
| 441 | pub fn resize(self: *Self, gpa: Allocator, new_len: usize) Allocator.Error!void { |
| 397 | 442 | try self.ensureTotalCapacity(gpa, new_len); |
| 398 | 443 | self.len = new_len; |
| 399 | 444 | } |
| ... | ... | @@ -479,14 +524,14 @@ pub fn MultiArrayList(comptime T: type) type { |
| 479 | 524 | |
| 480 | 525 | /// Modify the array so that it can hold at least `additional_count` **more** items. |
| 481 | 526 | /// Invalidates pointers if additional memory is needed. |
| 482 | | pub fn ensureUnusedCapacity(self: *Self, gpa: Allocator, additional_count: usize) !void { |
| 527 | pub fn ensureUnusedCapacity(self: *Self, gpa: Allocator, additional_count: usize) Allocator.Error!void { |
| 483 | 528 | return self.ensureTotalCapacity(gpa, self.len + additional_count); |
| 484 | 529 | } |
| 485 | 530 | |
| 486 | 531 | /// Modify the array so that it can hold exactly `new_capacity` items. |
| 487 | 532 | /// Invalidates pointers if additional memory is needed. |
| 488 | 533 | /// `new_capacity` must be greater or equal to `len`. |
| 489 | | pub fn setCapacity(self: *Self, gpa: Allocator, new_capacity: usize) !void { |
| 534 | pub fn setCapacity(self: *Self, gpa: Allocator, new_capacity: usize) Allocator.Error!void { |
| 490 | 535 | assert(new_capacity >= self.len); |
| 491 | 536 | const new_bytes = try gpa.alignedAlloc(u8, .of(Elem), capacityInBytes(new_capacity)); |
| 492 | 537 | if (self.len == 0) { |
| ... | ... | @@ -514,7 +559,7 @@ pub fn MultiArrayList(comptime T: type) type { |
| 514 | 559 | |
| 515 | 560 | /// Create a copy of this list with a new backing store, |
| 516 | 561 | /// using the specified allocator. |
| 517 | | pub fn clone(self: Self, gpa: Allocator) !Self { |
| 562 | pub fn clone(self: Self, gpa: Allocator) Allocator.Error!Self { |
| 518 | 563 | var result = Self{}; |
| 519 | 564 | errdefer result.deinit(gpa); |
| 520 | 565 | try result.ensureTotalCapacity(gpa, self.len); |
| ... | ... | @@ -654,7 +699,7 @@ test "basic usage" { |
| 654 | 699 | c: u8, |
| 655 | 700 | }; |
| 656 | 701 | |
| 657 | | var list = MultiArrayList(Foo){}; |
| 702 | var list: MultiArrayList(Foo) = .empty; |
| 658 | 703 | defer list.deinit(ally); |
| 659 | 704 | |
| 660 | 705 | try testing.expectEqual(@as(usize, 0), list.items(.a).len); |
| ... | ... | @@ -667,7 +712,7 @@ test "basic usage" { |
| 667 | 712 | .c = 'a', |
| 668 | 713 | }); |
| 669 | 714 | |
| 670 | | list.appendAssumeCapacity(.{ |
| 715 | try list.appendBounded(.{ |
| 671 | 716 | .a = 2, |
| 672 | 717 | .b = "zigzag", |
| 673 | 718 | .c = 'b', |
| ... | ... | @@ -725,6 +770,8 @@ test "basic usage" { |
| 725 | 770 | try testing.expectEqualStrings("zigzag", list.items(.b)[1]); |
| 726 | 771 | try testing.expectEqualStrings("fizzbuzz", list.items(.b)[2]); |
| 727 | 772 | |
| 773 | try testing.expectError(error.OutOfMemory, list.addOneBounded()); |
| 774 | |
| 728 | 775 | list.set(try list.addOne(ally), .{ |
| 729 | 776 | .a = 4, |
| 730 | 777 | .b = "xnopyt", |
| ... | ... | @@ -749,10 +796,10 @@ test "basic usage" { |
| 749 | 796 | // function used the @reduce code path. |
| 750 | 797 | test "regression test for @reduce bug" { |
| 751 | 798 | const ally = testing.allocator; |
| 752 | | var list = MultiArrayList(struct { |
| 799 | var list: MultiArrayList(struct { |
| 753 | 800 | tag: std.zig.Token.Tag, |
| 754 | 801 | start: u32, |
| 755 | | }){}; |
| 802 | }) = .empty; |
| 756 | 803 | defer list.deinit(ally); |
| 757 | 804 | |
| 758 | 805 | try list.ensureTotalCapacity(ally, 20); |
| ... | ... | @@ -832,7 +879,7 @@ test "ensure capacity on empty list" { |
| 832 | 879 | b: u8, |
| 833 | 880 | }; |
| 834 | 881 | |
| 835 | | var list = MultiArrayList(Foo){}; |
| 882 | var list: MultiArrayList(Foo) = .empty; |
| 836 | 883 | defer list.deinit(ally); |
| 837 | 884 | |
| 838 | 885 | try list.ensureTotalCapacity(ally, 2); |
| ... | ... | @@ -867,15 +914,25 @@ test "insert elements" { |
| 867 | 914 | b: u32, |
| 868 | 915 | }; |
| 869 | 916 | |
| 870 | | var list = MultiArrayList(Foo){}; |
| 917 | var list = try MultiArrayList(Foo).initCapacity(ally, 2); |
| 871 | 918 | defer list.deinit(ally); |
| 872 | 919 | |
| 873 | | try list.insert(ally, 0, .{ .a = 1, .b = 2 }); |
| 874 | | try list.ensureUnusedCapacity(ally, 1); |
| 920 | try list.insertBounded(0, .{ .a = 1, .b = 2 }); |
| 875 | 921 | list.insertAssumeCapacity(1, .{ .a = 2, .b = 3 }); |
| 922 | try list.insert(ally, 0, .{ .a = 3, .b = 4 }); |
| 923 | |
| 924 | try testing.expectEqualSlices(u8, &[_]u8{ 3, 1, 2 }, list.items(.a)); |
| 925 | try testing.expectEqualSlices(u32, &[_]u32{ 4, 2, 3 }, list.items(.b)); |
| 926 | } |
| 927 | |
| 928 | test "initCapacity" { |
| 929 | const gpa = testing.allocator; |
| 930 | |
| 931 | var list = try MultiArrayList(struct { a: u8, b: u32 }).initCapacity(gpa, 404); |
| 932 | defer list.deinit(gpa); |
| 876 | 933 | |
| 877 | | try testing.expectEqualSlices(u8, &[_]u8{ 1, 2 }, list.items(.a)); |
| 878 | | try testing.expectEqualSlices(u32, &[_]u32{ 2, 3 }, list.items(.b)); |
| 934 | try testing.expectEqual(0, list.len); |
| 935 | try testing.expectEqual(404, list.capacity); |
| 879 | 936 | } |
| 880 | 937 | |
| 881 | 938 | test "union" { |
| ... | ... | @@ -886,7 +943,7 @@ test "union" { |
| 886 | 943 | b: []const u8, |
| 887 | 944 | }; |
| 888 | 945 | |
| 889 | | var list = MultiArrayList(Foo){}; |
| 946 | var list: MultiArrayList(Foo) = .empty; |
| 890 | 947 | defer list.deinit(ally); |
| 891 | 948 | |
| 892 | 949 | try testing.expectEqual(@as(usize, 0), list.items(.tags).len); |
| ... | ... | @@ -934,7 +991,7 @@ test "union" { |
| 934 | 991 | } |
| 935 | 992 | |
| 936 | 993 | test "sorting a span" { |
| 937 | | var list: MultiArrayList(struct { score: u32, chr: u8 }) = .{}; |
| 994 | var list: MultiArrayList(struct { score: u32, chr: u8 }) = .empty; |
| 938 | 995 | defer list.deinit(testing.allocator); |
| 939 | 996 | |
| 940 | 997 | try list.ensureTotalCapacity(testing.allocator, 42); |
| ... | ... | @@ -981,7 +1038,7 @@ test "0 sized struct field" { |
| 981 | 1038 | b: f32, |
| 982 | 1039 | }; |
| 983 | 1040 | |
| 984 | | var list = MultiArrayList(Foo){}; |
| 1041 | var list: MultiArrayList(Foo) = .empty; |
| 985 | 1042 | defer list.deinit(ally); |
| 986 | 1043 | |
| 987 | 1044 | try testing.expectEqualSlices(u0, &[_]u0{}, list.items(.a)); |
| ... | ... | @@ -1007,7 +1064,7 @@ test "0 sized struct" { |
| 1007 | 1064 | a: u0, |
| 1008 | 1065 | }; |
| 1009 | 1066 | |
| 1010 | | var list = MultiArrayList(Foo){}; |
| 1067 | var list: MultiArrayList(Foo) = .empty; |
| 1011 | 1068 | defer list.deinit(ally); |
| 1012 | 1069 | |
| 1013 | 1070 | try testing.expectEqualSlices(u0, &[_]u0{}, list.items(.a)); |