| ... | @@ -244,27 +244,19 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -244,27 +244,19 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 244 | /// Invalidates element pointers if this ArrayList is resized. | 244 | /// Invalidates element pointers if this ArrayList is resized. |
| 245 | /// Asserts that the range is in bounds. | 245 | /// Asserts that the range is in bounds. |
| 246 | pub fn replaceRange(self: *Self, start: usize, len: usize, new_items: []const T) Allocator.Error!void { | 246 | pub fn replaceRange(self: *Self, start: usize, len: usize, new_items: []const T) Allocator.Error!void { |
| 247 | const after_range = start + len; | 247 | var unmanaged = self.moveToUnmanaged(); |
| 248 | const range = self.items[start..after_range]; | 248 | defer self.* = unmanaged.toManaged(self.allocator); |
| 249 | | 249 | return unmanaged.replaceRange(self.allocator, start, len, new_items); |
| 250 | if (range.len == new_items.len) | 250 | } |
| 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 | | 251 | |
| 266 | self.items.len -= len - new_items.len; | 252 | /// Replace range of elements `list[start..][0..len]` with `new_items`. |
| 267 | } | 253 | /// If `len < new_items.len` then it asserts that `.capacity` is |
| | 254 | /// large enough for the increase in items. |
| | 255 | /// Invalidates pointers if this ArrayList is resized. |
| | 256 | pub fn replaceRangeAssumeCapacity(self: *Self, start: usize, len: usize, new_items: []const T) void { |
| | 257 | var unmanaged = self.moveToUnmanaged(); |
| | 258 | unmanaged.replaceRangeAssumeCapacity(start, len, new_items); |
| | 259 | self.* = unmanaged.toManaged(self.allocator); |
| 268 | } | 260 | } |
| 269 | | 261 | |
| 270 | /// Extends the list by 1 element. Allocates more memory as necessary. | 262 | /// Extends the list by 1 element. Allocates more memory as necessary. |
| ... | @@ -290,13 +282,8 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -290,13 +282,8 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 290 | /// Asserts that the index is in bounds. | 282 | /// Asserts that the index is in bounds. |
| 291 | /// Asserts that the list is not empty. | 283 | /// Asserts that the list is not empty. |
| 292 | pub fn orderedRemove(self: *Self, i: usize) T { | 284 | 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]; | 285 | const old_item = self.items[i]; |
| 297 | for (self.items[i..newlen], 0..) |*b, j| b.* = self.items[i + 1 + j]; | 286 | self.replaceRangeAssumeCapacity(i, 1, &.{}); |
| 298 | self.items[newlen] = undefined; | | |
| 299 | self.items.len = newlen; | | |
| 300 | return old_item; | 287 | return old_item; |
| 301 | } | 288 | } |
| 302 | | 289 | |
| ... | @@ -820,9 +807,45 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ | ... | @@ -820,9 +807,45 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 820 | len: usize, | 807 | len: usize, |
| 821 | new_items: []const T, | 808 | new_items: []const T, |
| 822 | ) Allocator.Error!void { | 809 | ) Allocator.Error!void { |
| 823 | var managed = self.toManaged(allocator); | 810 | const after_range = start + len; |
| 824 | defer self.* = managed.moveToUnmanaged(); | 811 | const range = self.items[start..after_range]; |
| 825 | try managed.replaceRange(start, len, new_items); | 812 | if (range.len < new_items.len) { |
| | 813 | const first = new_items[0..range.len]; |
| | 814 | const rest = new_items[range.len..]; |
| | 815 | @memcpy(range[0..first.len], first); |
| | 816 | try self.insertSlice(allocator, after_range, rest); |
| | 817 | } else { |
| | 818 | self.replaceRangeAssumeCapacity(start, len, new_items); |
| | 819 | } |
| | 820 | } |
| | 821 | |
| | 822 | /// Replace range of elements `list[start..][0..len]` with `new_items`. |
| | 823 | /// Grows list if `len < new_items.len`. |
| | 824 | /// Shrinks list if `len > new_items.len`. |
| | 825 | /// Invalidates pointers if this ArrayList is resized. |
| | 826 | pub fn replaceRangeAssumeCapacity(self: *Self, start: usize, len: usize, new_items: []const T) void { |
| | 827 | const after_range = start + len; |
| | 828 | const range = self.items[start..after_range]; |
| | 829 | |
| | 830 | if (range.len == new_items.len) |
| | 831 | @memcpy(range[0..new_items.len], new_items) |
| | 832 | else if (range.len < new_items.len) { |
| | 833 | const first = new_items[0..range.len]; |
| | 834 | const rest = new_items[range.len..]; |
| | 835 | @memcpy(range[0..first.len], first); |
| | 836 | const dst = self.addManyAtAssumeCapacity(after_range, rest.len); |
| | 837 | @memcpy(dst, rest); |
| | 838 | } else { |
| | 839 | const extra = range.len - new_items.len; |
| | 840 | @memcpy(range[0..new_items.len], new_items); |
| | 841 | std.mem.copyForwards( |
| | 842 | T, |
| | 843 | self.items[after_range - extra ..], |
| | 844 | self.items[after_range..], |
| | 845 | ); |
| | 846 | @memset(self.items[self.items.len - extra ..], undefined); |
| | 847 | self.items.len -= extra; |
| | 848 | } |
| 826 | } | 849 | } |
| 827 | | 850 | |
| 828 | /// Extend the list by 1 element. Allocates more memory as necessary. | 851 | /// Extend the list by 1 element. Allocates more memory as necessary. |
| ... | @@ -846,13 +869,8 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ | ... | @@ -846,13 +869,8 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 846 | /// Asserts that the list is not empty. | 869 | /// Asserts that the list is not empty. |
| 847 | /// Asserts that the index is in bounds. | 870 | /// Asserts that the index is in bounds. |
| 848 | pub fn orderedRemove(self: *Self, i: usize) T { | 871 | 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]; | 872 | const old_item = self.items[i]; |
| 853 | for (self.items[i..newlen], 0..) |*b, j| b.* = self.items[i + 1 + j]; | 873 | self.replaceRangeAssumeCapacity(i, 1, &.{}); |
| 854 | self.items[newlen] = undefined; | | |
| 855 | self.items.len = newlen; | | |
| 856 | return old_item; | 874 | return old_item; |
| 857 | } | 875 | } |
| 858 | | 876 | |
| ... | @@ -1470,6 +1488,22 @@ test "std.ArrayList/ArrayListUnmanaged.orderedRemove" { | ... | @@ -1470,6 +1488,22 @@ test "std.ArrayList/ArrayListUnmanaged.orderedRemove" { |
| 1470 | try testing.expectEqual(@as(i32, 2), list.items[0]); | 1488 | try testing.expectEqual(@as(i32, 2), list.items[0]); |
| 1471 | try testing.expectEqual(@as(usize, 4), list.items.len); | 1489 | try testing.expectEqual(@as(usize, 4), list.items.len); |
| 1472 | } | 1490 | } |
| | 1491 | { |
| | 1492 | // remove last item |
| | 1493 | var list = ArrayList(i32).init(a); |
| | 1494 | defer list.deinit(); |
| | 1495 | try list.append(1); |
| | 1496 | try testing.expectEqual(@as(i32, 1), list.orderedRemove(0)); |
| | 1497 | try testing.expectEqual(@as(usize, 0), list.items.len); |
| | 1498 | } |
| | 1499 | { |
| | 1500 | // remove last item |
| | 1501 | var list = ArrayListUnmanaged(i32){}; |
| | 1502 | defer list.deinit(a); |
| | 1503 | try list.append(a, 1); |
| | 1504 | try testing.expectEqual(@as(i32, 1), list.orderedRemove(0)); |
| | 1505 | try testing.expectEqual(@as(usize, 0), list.items.len); |
| | 1506 | } |
| 1473 | } | 1507 | } |
| 1474 | | 1508 | |
| 1475 | test "std.ArrayList/ArrayListUnmanaged.swapRemove" { | 1509 | test "std.ArrayList/ArrayListUnmanaged.swapRemove" { |
| ... | @@ -1665,6 +1699,55 @@ test "std.ArrayList/ArrayListUnmanaged.replaceRange" { | ... | @@ -1665,6 +1699,55 @@ test "std.ArrayList/ArrayListUnmanaged.replaceRange" { |
| 1665 | try testing.expectEqualSlices(i32, list_lt.items, &result_le); | 1699 | try testing.expectEqualSlices(i32, list_lt.items, &result_le); |
| 1666 | try testing.expectEqualSlices(i32, list_gt.items, &result_gt); | 1700 | try testing.expectEqualSlices(i32, list_gt.items, &result_gt); |
| 1667 | } | 1701 | } |
| | 1702 | |
| | 1703 | { |
| | 1704 | var list_zero = ArrayList(i32).init(a); |
| | 1705 | var list_eq = ArrayList(i32).init(a); |
| | 1706 | var list_lt = ArrayList(i32).init(a); |
| | 1707 | var list_gt = ArrayList(i32).init(a); |
| | 1708 | |
| | 1709 | try list_zero.appendSlice(&init); |
| | 1710 | try list_eq.appendSlice(&init); |
| | 1711 | try list_lt.appendSlice(&init); |
| | 1712 | try list_gt.appendSlice(&init); |
| | 1713 | |
| | 1714 | list_zero.replaceRangeAssumeCapacity(1, 0, &new); |
| | 1715 | list_eq.replaceRangeAssumeCapacity(1, 3, &new); |
| | 1716 | list_lt.replaceRangeAssumeCapacity(1, 2, &new); |
| | 1717 | |
| | 1718 | // after_range > new_items.len in function body |
| | 1719 | try testing.expect(1 + 4 > new.len); |
| | 1720 | list_gt.replaceRangeAssumeCapacity(1, 4, &new); |
| | 1721 | |
| | 1722 | try testing.expectEqualSlices(i32, list_zero.items, &result_zero); |
| | 1723 | try testing.expectEqualSlices(i32, list_eq.items, &result_eq); |
| | 1724 | try testing.expectEqualSlices(i32, list_lt.items, &result_le); |
| | 1725 | try testing.expectEqualSlices(i32, list_gt.items, &result_gt); |
| | 1726 | } |
| | 1727 | { |
| | 1728 | var list_zero = ArrayListUnmanaged(i32){}; |
| | 1729 | var list_eq = ArrayListUnmanaged(i32){}; |
| | 1730 | var list_lt = ArrayListUnmanaged(i32){}; |
| | 1731 | var list_gt = ArrayListUnmanaged(i32){}; |
| | 1732 | |
| | 1733 | try list_zero.appendSlice(a, &init); |
| | 1734 | try list_eq.appendSlice(a, &init); |
| | 1735 | try list_lt.appendSlice(a, &init); |
| | 1736 | try list_gt.appendSlice(a, &init); |
| | 1737 | |
| | 1738 | list_zero.replaceRangeAssumeCapacity(1, 0, &new); |
| | 1739 | list_eq.replaceRangeAssumeCapacity(1, 3, &new); |
| | 1740 | list_lt.replaceRangeAssumeCapacity(1, 2, &new); |
| | 1741 | |
| | 1742 | // after_range > new_items.len in function body |
| | 1743 | try testing.expect(1 + 4 > new.len); |
| | 1744 | list_gt.replaceRangeAssumeCapacity(1, 4, &new); |
| | 1745 | |
| | 1746 | try testing.expectEqualSlices(i32, list_zero.items, &result_zero); |
| | 1747 | try testing.expectEqualSlices(i32, list_eq.items, &result_eq); |
| | 1748 | try testing.expectEqualSlices(i32, list_lt.items, &result_le); |
| | 1749 | try testing.expectEqualSlices(i32, list_gt.items, &result_gt); |
| | 1750 | } |
| 1668 | } | 1751 | } |
| 1669 | | 1752 | |
| 1670 | const Item = struct { | 1753 | const Item = struct { |