| ... | ... | @@ -244,27 +244,19 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 244 | 244 | /// Invalidates element pointers if this ArrayList is resized. |
| 245 | 245 | /// Asserts that the range is in bounds. |
| 246 | 246 | pub fn replaceRange(self: *Self, start: usize, len: usize, new_items: []const T) Allocator.Error!void { |
| 247 | | const after_range = start + len; |
| 248 | | const range = self.items[start..after_range]; |
| 249 | | |
| 250 | | if (range.len == new_items.len) |
| 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 | | } |
| 247 | var unmanaged = self.moveToUnmanaged(); |
| 248 | defer self.* = unmanaged.toManaged(self.allocator); |
| 249 | return unmanaged.replaceRange(self.allocator, start, len, new_items); |
| 250 | } |
| 265 | 251 | |
| 266 | | self.items.len -= len - new_items.len; |
| 267 | | } |
| 252 | /// Replace range of elements `list[start..][0..len]` with `new_items`. |
| 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 | 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 | 282 | /// Asserts that the index is in bounds. |
| 291 | 283 | /// Asserts that the list is not empty. |
| 292 | 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 | 285 | const old_item = self.items[i]; |
| 297 | | for (self.items[i..newlen], 0..) |*b, j| b.* = self.items[i + 1 + j]; |
| 298 | | self.items[newlen] = undefined; |
| 299 | | self.items.len = newlen; |
| 286 | self.replaceRangeAssumeCapacity(i, 1, &.{}); |
| 300 | 287 | return old_item; |
| 301 | 288 | } |
| 302 | 289 | |
| ... | ... | @@ -820,9 +807,45 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 820 | 807 | len: usize, |
| 821 | 808 | new_items: []const T, |
| 822 | 809 | ) Allocator.Error!void { |
| 823 | | var managed = self.toManaged(allocator); |
| 824 | | defer self.* = managed.moveToUnmanaged(); |
| 825 | | try managed.replaceRange(start, len, new_items); |
| 810 | const after_range = start + len; |
| 811 | const range = self.items[start..after_range]; |
| 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 | 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 | 869 | /// Asserts that the list is not empty. |
| 847 | 870 | /// Asserts that the index is in bounds. |
| 848 | 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 | 872 | const old_item = self.items[i]; |
| 853 | | for (self.items[i..newlen], 0..) |*b, j| b.* = self.items[i + 1 + j]; |
| 854 | | self.items[newlen] = undefined; |
| 855 | | self.items.len = newlen; |
| 873 | self.replaceRangeAssumeCapacity(i, 1, &.{}); |
| 856 | 874 | return old_item; |
| 857 | 875 | } |
| 858 | 876 | |
| ... | ... | @@ -1470,6 +1488,22 @@ test "std.ArrayList/ArrayListUnmanaged.orderedRemove" { |
| 1470 | 1488 | try testing.expectEqual(@as(i32, 2), list.items[0]); |
| 1471 | 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 | 1509 | test "std.ArrayList/ArrayListUnmanaged.swapRemove" { |
| ... | ... | @@ -1665,6 +1699,55 @@ test "std.ArrayList/ArrayListUnmanaged.replaceRange" { |
| 1665 | 1699 | try testing.expectEqualSlices(i32, list_lt.items, &result_le); |
| 1666 | 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 | 1753 | const Item = struct { |