| ... | ... | @@ -238,33 +238,22 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 238 | 238 | @memcpy(dst, items); |
| 239 | 239 | } |
| 240 | 240 | |
| 241 | | /// Replace range of elements `list[start..][0..len]` with `new_items`. |
| 242 | | /// Grows list if `len < new_items.len`. |
| 243 | | /// Shrinks list if `len > new_items.len`. |
| 244 | | /// Invalidates element pointers if this ArrayList is resized. |
| 241 | /// Grows or shrinks the list as necessary. |
| 242 | /// Invalidates element pointers if additional capacity is allocated. |
| 245 | 243 | /// Asserts that the range is in bounds. |
| 246 | 244 | 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 | | } |
| 245 | var unmanaged = self.moveToUnmanaged(); |
| 246 | defer self.* = unmanaged.toManaged(self.allocator); |
| 247 | return unmanaged.replaceRange(self.allocator, start, len, new_items); |
| 248 | } |
| 265 | 249 | |
| 266 | | self.items.len -= len - new_items.len; |
| 267 | | } |
| 250 | /// Grows or shrinks the list as necessary. |
| 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 | 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 | 279 | /// Asserts that the index is in bounds. |
| 291 | 280 | /// Asserts that the list is not empty. |
| 292 | 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 | 282 | 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; |
| 283 | self.replaceRangeAssumeCapacity(i, 1, &.{}); |
| 300 | 284 | return old_item; |
| 301 | 285 | } |
| 302 | 286 | |
| ... | ... | @@ -808,11 +792,9 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 808 | 792 | @memcpy(dst, items); |
| 809 | 793 | } |
| 810 | 794 | |
| 811 | | /// Replace range of elements `list[start..][0..len]` with `new_items` |
| 812 | | /// Grows list if `len < new_items.len`. |
| 813 | | /// Shrinks list if `len > new_items.len` |
| 814 | | /// Invalidates element pointers if this ArrayList is resized. |
| 815 | | /// Asserts that the start index is in bounds or equal to the length. |
| 795 | /// Grows or shrinks the list as necessary. |
| 796 | /// Invalidates element pointers if additional capacity is allocated. |
| 797 | /// Asserts that the range is in bounds. |
| 816 | 798 | pub fn replaceRange( |
| 817 | 799 | self: *Self, |
| 818 | 800 | allocator: Allocator, |
| ... | ... | @@ -820,9 +802,44 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 820 | 802 | len: usize, |
| 821 | 803 | new_items: []const T, |
| 822 | 804 | ) Allocator.Error!void { |
| 823 | | var managed = self.toManaged(allocator); |
| 824 | | defer self.* = managed.moveToUnmanaged(); |
| 825 | | try managed.replaceRange(start, len, new_items); |
| 805 | const after_range = start + len; |
| 806 | const range = self.items[start..after_range]; |
| 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 | 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 | 863 | /// Asserts that the list is not empty. |
| 847 | 864 | /// Asserts that the index is in bounds. |
| 848 | 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 | 866 | 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; |
| 867 | self.replaceRangeAssumeCapacity(i, 1, &.{}); |
| 856 | 868 | return old_item; |
| 857 | 869 | } |
| 858 | 870 | |
| ... | ... | @@ -1470,6 +1482,22 @@ test "std.ArrayList/ArrayListUnmanaged.orderedRemove" { |
| 1470 | 1482 | try testing.expectEqual(@as(i32, 2), list.items[0]); |
| 1471 | 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 | 1503 | test "std.ArrayList/ArrayListUnmanaged.swapRemove" { |
| ... | ... | @@ -1665,6 +1693,55 @@ test "std.ArrayList/ArrayListUnmanaged.replaceRange" { |
| 1665 | 1693 | try testing.expectEqualSlices(i32, list_lt.items, &result_le); |
| 1666 | 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 | 1747 | const Item = struct { |