mirror of
https://github.com/ziglang/zig.git
synced 2024-11-15 08:33:06 +00:00
Merge pull request #18293 from g-cassie/array-list-replace-range-assume
Add replaceRangeAssumeCapacity method to ArrayList
This commit is contained in:
commit
480a2f7f02
@ -238,33 +238,22 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
|
||||
@memcpy(dst, items);
|
||||
}
|
||||
|
||||
/// Replace range of elements `list[start..][0..len]` with `new_items`.
|
||||
/// Grows list if `len < new_items.len`.
|
||||
/// Shrinks list if `len > new_items.len`.
|
||||
/// Invalidates element pointers if this ArrayList is resized.
|
||||
/// Grows or shrinks the list as necessary.
|
||||
/// Invalidates element pointers if additional capacity is allocated.
|
||||
/// Asserts that the range is in bounds.
|
||||
pub fn replaceRange(self: *Self, start: usize, len: usize, new_items: []const T) Allocator.Error!void {
|
||||
const after_range = start + len;
|
||||
const range = self.items[start..after_range];
|
||||
var unmanaged = self.moveToUnmanaged();
|
||||
defer self.* = unmanaged.toManaged(self.allocator);
|
||||
return unmanaged.replaceRange(self.allocator, start, len, new_items);
|
||||
}
|
||||
|
||||
if (range.len == new_items.len)
|
||||
@memcpy(range[0..new_items.len], new_items)
|
||||
else if (range.len < new_items.len) {
|
||||
const first = new_items[0..range.len];
|
||||
const rest = new_items[range.len..];
|
||||
|
||||
@memcpy(range[0..first.len], first);
|
||||
try self.insertSlice(after_range, rest);
|
||||
} else {
|
||||
@memcpy(range[0..new_items.len], new_items);
|
||||
const after_subrange = start + new_items.len;
|
||||
|
||||
for (self.items[after_range..], 0..) |item, i| {
|
||||
self.items[after_subrange..][i] = item;
|
||||
}
|
||||
|
||||
self.items.len -= len - new_items.len;
|
||||
}
|
||||
/// Grows or shrinks the list as necessary.
|
||||
/// Never invalidates element pointers.
|
||||
/// Asserts the capacity is enough for additional items.
|
||||
pub fn replaceRangeAssumeCapacity(self: *Self, start: usize, len: usize, new_items: []const T) void {
|
||||
var unmanaged = self.moveToUnmanaged();
|
||||
defer self.* = unmanaged.toManaged(self.allocator);
|
||||
return unmanaged.replaceRangeAssumeCapacity(start, len, new_items);
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
/// Asserts that the index is in bounds.
|
||||
/// Asserts that the list is not empty.
|
||||
pub fn orderedRemove(self: *Self, i: usize) T {
|
||||
const newlen = self.items.len - 1;
|
||||
if (newlen == i) return self.pop();
|
||||
|
||||
const old_item = self.items[i];
|
||||
for (self.items[i..newlen], 0..) |*b, j| b.* = self.items[i + 1 + j];
|
||||
self.items[newlen] = undefined;
|
||||
self.items.len = newlen;
|
||||
self.replaceRangeAssumeCapacity(i, 1, &.{});
|
||||
return old_item;
|
||||
}
|
||||
|
||||
@ -808,11 +792,9 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
|
||||
@memcpy(dst, items);
|
||||
}
|
||||
|
||||
/// Replace range of elements `list[start..][0..len]` with `new_items`
|
||||
/// Grows list if `len < new_items.len`.
|
||||
/// Shrinks list if `len > new_items.len`
|
||||
/// Invalidates element pointers if this ArrayList is resized.
|
||||
/// Asserts that the start index is in bounds or equal to the length.
|
||||
/// Grows or shrinks the list as necessary.
|
||||
/// Invalidates element pointers if additional capacity is allocated.
|
||||
/// Asserts that the range is in bounds.
|
||||
pub fn replaceRange(
|
||||
self: *Self,
|
||||
allocator: Allocator,
|
||||
@ -820,9 +802,44 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
|
||||
len: usize,
|
||||
new_items: []const T,
|
||||
) Allocator.Error!void {
|
||||
var managed = self.toManaged(allocator);
|
||||
defer self.* = managed.moveToUnmanaged();
|
||||
try managed.replaceRange(start, len, new_items);
|
||||
const after_range = start + len;
|
||||
const range = self.items[start..after_range];
|
||||
if (range.len < new_items.len) {
|
||||
const first = new_items[0..range.len];
|
||||
const rest = new_items[range.len..];
|
||||
@memcpy(range[0..first.len], first);
|
||||
try self.insertSlice(allocator, after_range, rest);
|
||||
} else {
|
||||
self.replaceRangeAssumeCapacity(start, len, new_items);
|
||||
}
|
||||
}
|
||||
|
||||
/// Grows or shrinks the list as necessary.
|
||||
/// Never invalidates element pointers.
|
||||
/// Asserts the capacity is enough for additional items.
|
||||
pub fn replaceRangeAssumeCapacity(self: *Self, start: usize, len: usize, new_items: []const T) void {
|
||||
const after_range = start + len;
|
||||
const range = self.items[start..after_range];
|
||||
|
||||
if (range.len == new_items.len)
|
||||
@memcpy(range[0..new_items.len], new_items)
|
||||
else if (range.len < new_items.len) {
|
||||
const first = new_items[0..range.len];
|
||||
const rest = new_items[range.len..];
|
||||
@memcpy(range[0..first.len], first);
|
||||
const dst = self.addManyAtAssumeCapacity(after_range, rest.len);
|
||||
@memcpy(dst, rest);
|
||||
} else {
|
||||
const extra = range.len - new_items.len;
|
||||
@memcpy(range[0..new_items.len], new_items);
|
||||
std.mem.copyForwards(
|
||||
T,
|
||||
self.items[after_range - extra ..],
|
||||
self.items[after_range..],
|
||||
);
|
||||
@memset(self.items[self.items.len - extra ..], undefined);
|
||||
self.items.len -= extra;
|
||||
}
|
||||
}
|
||||
|
||||
/// 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
|
||||
/// Asserts that the list is not empty.
|
||||
/// Asserts that the index is in bounds.
|
||||
pub fn orderedRemove(self: *Self, i: usize) T {
|
||||
const newlen = self.items.len - 1;
|
||||
if (newlen == i) return self.pop();
|
||||
|
||||
const old_item = self.items[i];
|
||||
for (self.items[i..newlen], 0..) |*b, j| b.* = self.items[i + 1 + j];
|
||||
self.items[newlen] = undefined;
|
||||
self.items.len = newlen;
|
||||
self.replaceRangeAssumeCapacity(i, 1, &.{});
|
||||
return old_item;
|
||||
}
|
||||
|
||||
@ -1470,6 +1482,22 @@ test "std.ArrayList/ArrayListUnmanaged.orderedRemove" {
|
||||
try testing.expectEqual(@as(i32, 2), list.items[0]);
|
||||
try testing.expectEqual(@as(usize, 4), list.items.len);
|
||||
}
|
||||
{
|
||||
// remove last item
|
||||
var list = ArrayList(i32).init(a);
|
||||
defer list.deinit();
|
||||
try list.append(1);
|
||||
try testing.expectEqual(@as(i32, 1), list.orderedRemove(0));
|
||||
try testing.expectEqual(@as(usize, 0), list.items.len);
|
||||
}
|
||||
{
|
||||
// remove last item
|
||||
var list = ArrayListUnmanaged(i32){};
|
||||
defer list.deinit(a);
|
||||
try list.append(a, 1);
|
||||
try testing.expectEqual(@as(i32, 1), list.orderedRemove(0));
|
||||
try testing.expectEqual(@as(usize, 0), list.items.len);
|
||||
}
|
||||
}
|
||||
|
||||
test "std.ArrayList/ArrayListUnmanaged.swapRemove" {
|
||||
@ -1665,6 +1693,55 @@ test "std.ArrayList/ArrayListUnmanaged.replaceRange" {
|
||||
try testing.expectEqualSlices(i32, list_lt.items, &result_le);
|
||||
try testing.expectEqualSlices(i32, list_gt.items, &result_gt);
|
||||
}
|
||||
|
||||
{
|
||||
var list_zero = ArrayList(i32).init(a);
|
||||
var list_eq = ArrayList(i32).init(a);
|
||||
var list_lt = ArrayList(i32).init(a);
|
||||
var list_gt = ArrayList(i32).init(a);
|
||||
|
||||
try list_zero.appendSlice(&init);
|
||||
try list_eq.appendSlice(&init);
|
||||
try list_lt.appendSlice(&init);
|
||||
try list_gt.appendSlice(&init);
|
||||
|
||||
list_zero.replaceRangeAssumeCapacity(1, 0, &new);
|
||||
list_eq.replaceRangeAssumeCapacity(1, 3, &new);
|
||||
list_lt.replaceRangeAssumeCapacity(1, 2, &new);
|
||||
|
||||
// after_range > new_items.len in function body
|
||||
try testing.expect(1 + 4 > new.len);
|
||||
list_gt.replaceRangeAssumeCapacity(1, 4, &new);
|
||||
|
||||
try testing.expectEqualSlices(i32, list_zero.items, &result_zero);
|
||||
try testing.expectEqualSlices(i32, list_eq.items, &result_eq);
|
||||
try testing.expectEqualSlices(i32, list_lt.items, &result_le);
|
||||
try testing.expectEqualSlices(i32, list_gt.items, &result_gt);
|
||||
}
|
||||
{
|
||||
var list_zero = ArrayListUnmanaged(i32){};
|
||||
var list_eq = ArrayListUnmanaged(i32){};
|
||||
var list_lt = ArrayListUnmanaged(i32){};
|
||||
var list_gt = ArrayListUnmanaged(i32){};
|
||||
|
||||
try list_zero.appendSlice(a, &init);
|
||||
try list_eq.appendSlice(a, &init);
|
||||
try list_lt.appendSlice(a, &init);
|
||||
try list_gt.appendSlice(a, &init);
|
||||
|
||||
list_zero.replaceRangeAssumeCapacity(1, 0, &new);
|
||||
list_eq.replaceRangeAssumeCapacity(1, 3, &new);
|
||||
list_lt.replaceRangeAssumeCapacity(1, 2, &new);
|
||||
|
||||
// after_range > new_items.len in function body
|
||||
try testing.expect(1 + 4 > new.len);
|
||||
list_gt.replaceRangeAssumeCapacity(1, 4, &new);
|
||||
|
||||
try testing.expectEqualSlices(i32, list_zero.items, &result_zero);
|
||||
try testing.expectEqualSlices(i32, list_eq.items, &result_eq);
|
||||
try testing.expectEqualSlices(i32, list_lt.items, &result_le);
|
||||
try testing.expectEqualSlices(i32, list_gt.items, &result_gt);
|
||||
}
|
||||
}
|
||||
|
||||
const Item = struct {
|
||||
|
Loading…
Reference in New Issue
Block a user