authorgravatar for red.black.liquorice@gmail.comHila Friedman <red.black.liquorice@gmail.com> 2026-04-02 15:11:24+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-04-02 15:11:24+02:00
log746dd51fafa8cdc8d98500af3b3b4b659c1aef92
treef406c0532716f162451b1a327cd7300d31f40e18
parentf4eecf8d7d4026a9e0ab8986b1c049ad2a0e01fc

Simplify `std.ArrayList.replaceRange` and `std.ArrayList.replaceRangeAssumeCapacity` (#31710)

The implementations of `std.ArrayList.replaceRange` and `std.ArrayList.replaceRangeAssumeCapacity` were needlessly complicated, called `@memcpy` too many times, and left the structure in a semi-modified state in OOM conditions. This commit fixes that. Reviewed-on: https://codeberg.org/ziglang/zig/pulls/31710 Reviewed-by: Andrew Kelley <andrew@ziglang.org> Co-authored-by: Hila Friedman <red.black.liquorice@gmail.com> Co-committed-by: Hila Friedman <red.black.liquorice@gmail.com>

1 files changed, 22 insertions(+), 31 deletions(-)

lib/std/array_list.zig+22-31
...@@ -857,16 +857,8 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {...@@ -857,16 +857,8 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
857 len: usize,857 len: usize,
858 new_items: []const T,858 new_items: []const T,
859 ) Allocator.Error!void {859 ) Allocator.Error!void {
860 const after_range = start + len;860 try self.ensureTotalCapacity(gpa, try addOrOom(self.items.len - len, new_items.len));
861 const range = self.items[start..after_range];861 self.replaceRangeAssumeCapacity(start, len, new_items);
862 if (range.len < new_items.len) {
863 const first = new_items[0..range.len];
864 const rest = new_items[range.len..];
865 @memcpy(range[0..first.len], first);
866 try self.insertSlice(gpa, after_range, rest);
867 } else {
868 self.replaceRangeAssumeCapacity(start, len, new_items);
869 }
870 }862 }
871863
872 /// Grows or shrinks the list as necessary.864 /// Grows or shrinks the list as necessary.
...@@ -874,26 +866,20 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {...@@ -874,26 +866,20 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
874 /// Never invalidates element pointers.866 /// Never invalidates element pointers.
875 ///867 ///
876 /// Asserts the capacity is enough for additional items.868 /// Asserts the capacity is enough for additional items.
877 pub fn replaceRangeAssumeCapacity(self: *Self, start: usize, len: usize, new_items: []const T) void {869 pub fn replaceRangeAssumeCapacity(
878 const after_range = start + len;870 self: *Self,
879 const range = self.items[start..after_range];871 start: usize,
880872 len: usize,
881 if (range.len == new_items.len)873 new_items: []const T,
882 @memcpy(range[0..new_items.len], new_items)874 ) void {
883 else if (range.len < new_items.len) {875 std.debug.assert(self.capacity - self.items.len >= new_items.len -| len);
884 const first = new_items[0..range.len];876
885 const rest = new_items[range.len..];877 const tail = self.items[start + len ..];
886 @memcpy(range[0..first.len], first);878 const vacated = self.items[self.items.len - (len -| new_items.len) ..];
887 const dst = self.addManyAtAssumeCapacity(after_range, rest.len);879 self.items.len = self.items.len - len + new_items.len;
888 @memcpy(dst, rest);880 @memmove(self.items[start + new_items.len ..], tail);
889 } else {881 @memcpy(self.items[start..][0..new_items.len], new_items);
890 const extra = range.len - new_items.len;882 @memset(vacated, undefined);
891 @memcpy(range[0..new_items.len], new_items);
892 const src = self.items[after_range..];
893 @memmove(self.items[after_range - extra ..][0..src.len], src);
894 @memset(self.items[self.items.len - extra ..], undefined);
895 self.items.len -= extra;
896 }
897 }883 }
898884
899 /// Grows or shrinks the list as necessary.885 /// Grows or shrinks the list as necessary.
...@@ -902,7 +888,12 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {...@@ -902,7 +888,12 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
902 ///888 ///
903 /// If the unused capacity is insufficient for additional items,889 /// If the unused capacity is insufficient for additional items,
904 /// returns `error.OutOfMemory`.890 /// returns `error.OutOfMemory`.
905 pub fn replaceRangeBounded(self: *Self, start: usize, len: usize, new_items: []const T) error{OutOfMemory}!void {891 pub fn replaceRangeBounded(
892 self: *Self,
893 start: usize,
894 len: usize,
895 new_items: []const T,
896 ) error{OutOfMemory}!void {
906 if (self.capacity - self.items.len < new_items.len -| len) return error.OutOfMemory;897 if (self.capacity - self.items.len < new_items.len -| len) return error.OutOfMemory;
907 return replaceRangeAssumeCapacity(self, start, len, new_items);898 return replaceRangeAssumeCapacity(self, start, len, new_items);
908 }899 }