| ... | @@ -238,33 +238,22 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -238,33 +238,22 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 238 | @memcpy(dst, items); | 238 | @memcpy(dst, items); |
| 239 | } | 239 | } |
| 240 | | 240 | |
| 241 | /// Replace range of elements `list[start..][0..len]` with `new_items`. | 241 | /// Grows or shrinks the list as necessary. |
| 242 | /// Grows list if `len < new_items.len`. | 242 | /// Invalidates element pointers if additional capacity is allocated. |
| 243 | /// Shrinks list if `len > new_items.len`. | | |
| 244 | /// Invalidates element pointers if this ArrayList is resized. | | |
| 245 | /// Asserts that the range is in bounds. | 243 | /// Asserts that the range is in bounds. |
| 246 | pub fn replaceRange(self: *Self, start: usize, len: usize, new_items: []const T) Allocator.Error!void { | 244 | pub fn replaceRange(self: *Self, start: usize, len: usize, new_items: []const T) Allocator.Error!void { |
| 247 | const after_range = start + len; | 245 | var unmanaged = self.moveToUnmanaged(); |
| 248 | const range = self.items[start..after_range]; | 246 | defer self.* = unmanaged.toManaged(self.allocator); |
| 249 | | 247 | return unmanaged.replaceRange(self.allocator, start, len, new_items); |
| 250 | if (range.len == new_items.len) | 248 | } |
| 251 | @memcpy(range[0..new_items.len], new_items) | | |
| 252 | else if (range.len < new_items.len) { | | |
| 253 | const first = new_items[0..range.len]; | | |
| 254 | const rest = new_items[range.len..]; | | |
| 255 | | | |
| 256 | @memcpy(range[0..first.len], first); | | |
| 257 | try self.insertSlice(after_range, rest); | | |
| 258 | } else { | | |
| 259 | @memcpy(range[0..new_items.len], new_items); | | |
| 260 | const after_subrange = start + new_items.len; | | |
| 261 | | | |
| 262 | for (self.items[after_range..], 0..) |item, i| { | | |
| 263 | self.items[after_subrange..][i] = item; | | |
| 264 | } | | |
| 265 | | 249 | |
| 266 | self.items.len -= len - new_items.len; | 250 | /// Grows or shrinks the list as necessary. |
| 267 | } | 251 | /// Never invalidates element pointers. |
| | 252 | /// Asserts the capacity is enough for additional items. |
| | 253 | pub fn replaceRangeAssumeCapacity(self: *Self, start: usize, len: usize, new_items: []const T) void { |
| | 254 | var unmanaged = self.moveToUnmanaged(); |
| | 255 | defer self.* = unmanaged.toManaged(self.allocator); |
| | 256 | return unmanaged.replaceRangeAssumeCapacity(start, len, new_items); |
| 268 | } | 257 | } |
| 269 | | 258 | |
| 270 | /// Extends the list by 1 element. Allocates more memory as necessary. | 259 | /// Extends the list by 1 element. Allocates more memory as necessary. |
| ... | @@ -290,13 +279,8 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -290,13 +279,8 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 290 | /// Asserts that the index is in bounds. | 279 | /// Asserts that the index is in bounds. |
| 291 | /// Asserts that the list is not empty. | 280 | /// Asserts that the list is not empty. |
| 292 | pub fn orderedRemove(self: *Self, i: usize) T { | 281 | pub fn orderedRemove(self: *Self, i: usize) T { |
| 293 | const newlen = self.items.len - 1; | | |
| 294 | if (newlen == i) return self.pop(); | | |
| 295 | | | |
| 296 | const old_item = self.items[i]; | 282 | const old_item = self.items[i]; |
| 297 | for (self.items[i..newlen], 0..) |*b, j| b.* = self.items[i + 1 + j]; | 283 | self.replaceRangeAssumeCapacity(i, 1, &.{}); |
| 298 | self.items[newlen] = undefined; | | |
| 299 | self.items.len = newlen; | | |
| 300 | return old_item; | 284 | return old_item; |
| 301 | } | 285 | } |
| 302 | | 286 | |
| ... | @@ -808,11 +792,9 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ | ... | @@ -808,11 +792,9 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 808 | @memcpy(dst, items); | 792 | @memcpy(dst, items); |
| 809 | } | 793 | } |
| 810 | | 794 | |
| 811 | /// Replace range of elements `list[start..][0..len]` with `new_items` | 795 | /// Grows or shrinks the list as necessary. |
| 812 | /// Grows list if `len < new_items.len`. | 796 | /// Invalidates element pointers if additional capacity is allocated. |
| 813 | /// Shrinks list if `len > new_items.len` | 797 | /// Asserts that the range is in bounds. |
| 814 | /// Invalidates element pointers if this ArrayList is resized. | | |
| 815 | /// Asserts that the start index is in bounds or equal to the length. | | |
| 816 | pub fn replaceRange( | 798 | pub fn replaceRange( |
| 817 | self: *Self, | 799 | self: *Self, |
| 818 | allocator: Allocator, | 800 | allocator: Allocator, |
| ... | @@ -820,9 +802,44 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ | ... | @@ -820,9 +802,44 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 820 | len: usize, | 802 | len: usize, |
| 821 | new_items: []const T, | 803 | new_items: []const T, |
| 822 | ) Allocator.Error!void { | 804 | ) Allocator.Error!void { |
| 823 | var managed = self.toManaged(allocator); | 805 | const after_range = start + len; |
| 824 | defer self.* = managed.moveToUnmanaged(); | 806 | const range = self.items[start..after_range]; |
| 825 | try managed.replaceRange(start, len, new_items); | 807 | if (range.len < new_items.len) { |
| | 808 | const first = new_items[0..range.len]; |
| | 809 | const rest = new_items[range.len..]; |
| | 810 | @memcpy(range[0..first.len], first); |
| | 811 | try self.insertSlice(allocator, after_range, rest); |
| | 812 | } else { |
| | 813 | self.replaceRangeAssumeCapacity(start, len, new_items); |
| | 814 | } |
| | 815 | } |
| | 816 | |
| | 817 | /// Grows or shrinks the list as necessary. |
| | 818 | /// Never invalidates element pointers. |
| | 819 | /// Asserts the capacity is enough for additional items. |
| | 820 | pub fn replaceRangeAssumeCapacity(self: *Self, start: usize, len: usize, new_items: []const T) void { |
| | 821 | const after_range = start + len; |
| | 822 | const range = self.items[start..after_range]; |
| | 823 | |
| | 824 | if (range.len == new_items.len) |
| | 825 | @memcpy(range[0..new_items.len], new_items) |
| | 826 | else if (range.len < new_items.len) { |
| | 827 | const first = new_items[0..range.len]; |
| | 828 | const rest = new_items[range.len..]; |
| | 829 | @memcpy(range[0..first.len], first); |
| | 830 | const dst = self.addManyAtAssumeCapacity(after_range, rest.len); |
| | 831 | @memcpy(dst, rest); |
| | 832 | } else { |
| | 833 | const extra = range.len - new_items.len; |
| | 834 | @memcpy(range[0..new_items.len], new_items); |
| | 835 | std.mem.copyForwards( |
| | 836 | T, |
| | 837 | self.items[after_range - extra ..], |
| | 838 | self.items[after_range..], |
| | 839 | ); |
| | 840 | @memset(self.items[self.items.len - extra ..], undefined); |
| | 841 | self.items.len -= extra; |
| | 842 | } |
| 826 | } | 843 | } |
| 827 | | 844 | |
| 828 | /// Extend the list by 1 element. Allocates more memory as necessary. | 845 | /// Extend the list by 1 element. Allocates more memory as necessary. |
| ... | @@ -846,13 +863,8 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ | ... | @@ -846,13 +863,8 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 846 | /// Asserts that the list is not empty. | 863 | /// Asserts that the list is not empty. |
| 847 | /// Asserts that the index is in bounds. | 864 | /// Asserts that the index is in bounds. |
| 848 | pub fn orderedRemove(self: *Self, i: usize) T { | 865 | pub fn orderedRemove(self: *Self, i: usize) T { |
| 849 | const newlen = self.items.len - 1; | | |
| 850 | if (newlen == i) return self.pop(); | | |
| 851 | | | |
| 852 | const old_item = self.items[i]; | 866 | const old_item = self.items[i]; |
| 853 | for (self.items[i..newlen], 0..) |*b, j| b.* = self.items[i + 1 + j]; | 867 | self.replaceRangeAssumeCapacity(i, 1, &.{}); |
| 854 | self.items[newlen] = undefined; | | |
| 855 | self.items.len = newlen; | | |
| 856 | return old_item; | 868 | return old_item; |
| 857 | } | 869 | } |
| 858 | | 870 | |
| ... | @@ -1470,6 +1482,22 @@ test "std.ArrayList/ArrayListUnmanaged.orderedRemove" { | ... | @@ -1470,6 +1482,22 @@ test "std.ArrayList/ArrayListUnmanaged.orderedRemove" { |
| 1470 | try testing.expectEqual(@as(i32, 2), list.items[0]); | 1482 | try testing.expectEqual(@as(i32, 2), list.items[0]); |
| 1471 | try testing.expectEqual(@as(usize, 4), list.items.len); | 1483 | try testing.expectEqual(@as(usize, 4), list.items.len); |
| 1472 | } | 1484 | } |
| | 1485 | { |
| | 1486 | // remove last item |
| | 1487 | var list = ArrayList(i32).init(a); |
| | 1488 | defer list.deinit(); |
| | 1489 | try list.append(1); |
| | 1490 | try testing.expectEqual(@as(i32, 1), list.orderedRemove(0)); |
| | 1491 | try testing.expectEqual(@as(usize, 0), list.items.len); |
| | 1492 | } |
| | 1493 | { |
| | 1494 | // remove last item |
| | 1495 | var list = ArrayListUnmanaged(i32){}; |
| | 1496 | defer list.deinit(a); |
| | 1497 | try list.append(a, 1); |
| | 1498 | try testing.expectEqual(@as(i32, 1), list.orderedRemove(0)); |
| | 1499 | try testing.expectEqual(@as(usize, 0), list.items.len); |
| | 1500 | } |
| 1473 | } | 1501 | } |
| 1474 | | 1502 | |
| 1475 | test "std.ArrayList/ArrayListUnmanaged.swapRemove" { | 1503 | test "std.ArrayList/ArrayListUnmanaged.swapRemove" { |
| ... | @@ -1665,6 +1693,55 @@ test "std.ArrayList/ArrayListUnmanaged.replaceRange" { | ... | @@ -1665,6 +1693,55 @@ test "std.ArrayList/ArrayListUnmanaged.replaceRange" { |
| 1665 | try testing.expectEqualSlices(i32, list_lt.items, &result_le); | 1693 | try testing.expectEqualSlices(i32, list_lt.items, &result_le); |
| 1666 | try testing.expectEqualSlices(i32, list_gt.items, &result_gt); | 1694 | try testing.expectEqualSlices(i32, list_gt.items, &result_gt); |
| 1667 | } | 1695 | } |
| | 1696 | |
| | 1697 | { |
| | 1698 | var list_zero = ArrayList(i32).init(a); |
| | 1699 | var list_eq = ArrayList(i32).init(a); |
| | 1700 | var list_lt = ArrayList(i32).init(a); |
| | 1701 | var list_gt = ArrayList(i32).init(a); |
| | 1702 | |
| | 1703 | try list_zero.appendSlice(&init); |
| | 1704 | try list_eq.appendSlice(&init); |
| | 1705 | try list_lt.appendSlice(&init); |
| | 1706 | try list_gt.appendSlice(&init); |
| | 1707 | |
| | 1708 | list_zero.replaceRangeAssumeCapacity(1, 0, &new); |
| | 1709 | list_eq.replaceRangeAssumeCapacity(1, 3, &new); |
| | 1710 | list_lt.replaceRangeAssumeCapacity(1, 2, &new); |
| | 1711 | |
| | 1712 | // after_range > new_items.len in function body |
| | 1713 | try testing.expect(1 + 4 > new.len); |
| | 1714 | list_gt.replaceRangeAssumeCapacity(1, 4, &new); |
| | 1715 | |
| | 1716 | try testing.expectEqualSlices(i32, list_zero.items, &result_zero); |
| | 1717 | try testing.expectEqualSlices(i32, list_eq.items, &result_eq); |
| | 1718 | try testing.expectEqualSlices(i32, list_lt.items, &result_le); |
| | 1719 | try testing.expectEqualSlices(i32, list_gt.items, &result_gt); |
| | 1720 | } |
| | 1721 | { |
| | 1722 | var list_zero = ArrayListUnmanaged(i32){}; |
| | 1723 | var list_eq = ArrayListUnmanaged(i32){}; |
| | 1724 | var list_lt = ArrayListUnmanaged(i32){}; |
| | 1725 | var list_gt = ArrayListUnmanaged(i32){}; |
| | 1726 | |
| | 1727 | try list_zero.appendSlice(a, &init); |
| | 1728 | try list_eq.appendSlice(a, &init); |
| | 1729 | try list_lt.appendSlice(a, &init); |
| | 1730 | try list_gt.appendSlice(a, &init); |
| | 1731 | |
| | 1732 | list_zero.replaceRangeAssumeCapacity(1, 0, &new); |
| | 1733 | list_eq.replaceRangeAssumeCapacity(1, 3, &new); |
| | 1734 | list_lt.replaceRangeAssumeCapacity(1, 2, &new); |
| | 1735 | |
| | 1736 | // after_range > new_items.len in function body |
| | 1737 | try testing.expect(1 + 4 > new.len); |
| | 1738 | list_gt.replaceRangeAssumeCapacity(1, 4, &new); |
| | 1739 | |
| | 1740 | try testing.expectEqualSlices(i32, list_zero.items, &result_zero); |
| | 1741 | try testing.expectEqualSlices(i32, list_eq.items, &result_eq); |
| | 1742 | try testing.expectEqualSlices(i32, list_lt.items, &result_le); |
| | 1743 | try testing.expectEqualSlices(i32, list_gt.items, &result_gt); |
| | 1744 | } |
| 1668 | } | 1745 | } |
| 1669 | | 1746 | |
| 1670 | const Item = struct { | 1747 | const Item = struct { |