authorgravatar for gordoncassie@gmail.comGordon Cassie <gordoncassie@gmail.com> 2023-12-14 16:03:36-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-01-19 16:24:51-07:00
log4ddd0b1a1bbcb18fa34dc5c1ab2d4f427df376b3
tree6ba69753968488b0440013e4dad629856dc37eab
parentd7b6d637df5b94ec07cf017fa742e8c34a4b9433

std.ArrayList: add replaceRangeAssumeCapacity method


1 files changed, 118 insertions(+), 35 deletions(-)

lib/std/array_list.zig+118-35
......@@ -244,27 +244,19 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
244244 /// Invalidates element pointers if this ArrayList is resized.
245245 /// Asserts that the range is in bounds.
246246 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 }
265251
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);
268260 }
269261
270262 /// 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 {
290282 /// Asserts that the index is in bounds.
291283 /// Asserts that the list is not empty.
292284 pub fn orderedRemove(self: *Self, i: usize) T {
293 const newlen = self.items.len - 1;
294 if (newlen == i) return self.pop();
295
296285 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, &.{});
300287 return old_item;
301288 }
302289
......@@ -820,9 +807,45 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
820807 len: usize,
821808 new_items: []const T,
822809 ) 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 }
826849 }
827850
828851 /// 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
846869 /// Asserts that the list is not empty.
847870 /// Asserts that the index is in bounds.
848871 pub fn orderedRemove(self: *Self, i: usize) T {
849 const newlen = self.items.len - 1;
850 if (newlen == i) return self.pop();
851
852872 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, &.{});
856874 return old_item;
857875 }
858876
......@@ -1470,6 +1488,22 @@ test "std.ArrayList/ArrayListUnmanaged.orderedRemove" {
14701488 try testing.expectEqual(@as(i32, 2), list.items[0]);
14711489 try testing.expectEqual(@as(usize, 4), list.items.len);
14721490 }
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 }
14731507}
14741508
14751509test "std.ArrayList/ArrayListUnmanaged.swapRemove" {
......@@ -1665,6 +1699,55 @@ test "std.ArrayList/ArrayListUnmanaged.replaceRange" {
16651699 try testing.expectEqualSlices(i32, list_lt.items, &result_le);
16661700 try testing.expectEqualSlices(i32, list_gt.items, &result_gt);
16671701 }
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 }
16681751}
16691752
16701753const Item = struct {