remove iterator API from std.ArrayList

This is not a meaningful abstraction. Use a for loop on the result
of `toSlice` or `toSliceConst`.

An iterator can be implemented on top of ArrayList by applications which
want additional functionality, such as removing elements while
iterating.

Closes #3037.
This commit is contained in:
Andrew Kelley 2019-12-10 15:08:10 -05:00
parent f30af12bea
commit c3d8b1ffeb
No known key found for this signature in database
GPG Key ID: 7C5F548F728501A9
2 changed files with 31 additions and 103 deletions

View File

@ -84,11 +84,6 @@ pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type {
self.items[i] = item;
}
/// Return length of the list.
pub fn count(self: Self) usize {
return self.len;
}
/// Return the maximum number of items the list can hold
/// without allocating more memory.
pub fn capacity(self: Self) usize {
@ -114,7 +109,7 @@ pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type {
return result;
}
/// Insert `item` at index `n`. Moves `list[n .. list.count()]`
/// Insert `item` at index `n`. Moves `list[n .. list.len]`
/// to make room.
pub fn insert(self: *Self, n: usize, item: T) !void {
try self.ensureCapacity(self.len + 1);
@ -125,7 +120,7 @@ pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type {
}
/// Insert slice `items` at index `n`. Moves
/// `list[n .. list.count()]` to make room.
/// `list[n .. list.len]` to make room.
pub fn insertSlice(self: *Self, n: usize, items: SliceConst) !void {
try self.ensureCapacity(self.len + items.len);
self.len += items.len;
@ -222,7 +217,7 @@ pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type {
}
pub fn addOneAssumeCapacity(self: *Self) *T {
assert(self.count() < self.capacity());
assert(self.len < self.capacity());
const result = &self.items[self.len];
self.len += 1;
return result;
@ -240,31 +235,6 @@ pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type {
if (self.len == 0) return null;
return self.pop();
}
pub const Iterator = struct {
list: *const Self,
// how many items have we returned
count: usize,
pub fn next(it: *Iterator) ?T {
if (it.count >= it.list.len) return null;
const val = it.list.at(it.count);
it.count += 1;
return val;
}
pub fn reset(it: *Iterator) void {
it.count = 0;
}
};
/// Return an iterator over the list.
pub fn iterator(self: *const Self) Iterator {
return Iterator{
.list = self,
.count = 0,
};
}
};
}
@ -275,7 +245,7 @@ test "std.ArrayList.init" {
var list = ArrayList(i32).init(allocator);
defer list.deinit();
testing.expect(list.count() == 0);
testing.expect(list.len == 0);
testing.expect(list.capacity() == 0);
}
@ -284,7 +254,7 @@ test "std.ArrayList.initCapacity" {
const allocator = &std.heap.FixedBufferAllocator.init(bytes[0..]).allocator;
var list = try ArrayList(i8).initCapacity(allocator, 200);
defer list.deinit();
testing.expect(list.count() == 0);
testing.expect(list.len == 0);
testing.expect(list.capacity() >= 200);
}
@ -426,35 +396,6 @@ test "std.ArrayList.swapRemoveOrError" {
testing.expectError(error.OutOfBounds, list.swapRemoveOrError(2));
}
test "std.ArrayList.iterator" {
var list = ArrayList(i32).init(debug.global_allocator);
defer list.deinit();
try list.append(1);
try list.append(2);
try list.append(3);
var count: i32 = 0;
var it = list.iterator();
while (it.next()) |next| {
testing.expect(next == count + 1);
count += 1;
}
testing.expect(count == 3);
testing.expect(it.next() == null);
it.reset();
count = 0;
while (it.next()) |next| {
testing.expect(next == count + 1);
count += 1;
if (count == 2) break;
}
it.reset();
testing.expect(it.next().? == 1);
}
test "std.ArrayList.insert" {
var list = ArrayList(i32).init(debug.global_allocator);
defer list.deinit();

View File

@ -133,8 +133,7 @@ pub const Headers = struct {
self.index.deinit();
}
{
var it = self.data.iterator();
while (it.next()) |entry| {
for (self.data.toSliceConst()) |entry| {
entry.deinit();
}
self.data.deinit();
@ -144,27 +143,20 @@ pub const Headers = struct {
pub fn clone(self: Self, allocator: *Allocator) !Self {
var other = Headers.init(allocator);
errdefer other.deinit();
try other.data.ensureCapacity(self.data.count());
try other.data.ensureCapacity(self.data.len);
try other.index.initCapacity(self.index.entries.len);
var it = self.data.iterator();
while (it.next()) |entry| {
for (self.data.toSliceConst()) |entry| {
try other.append(entry.name, entry.value, entry.never_index);
}
return other;
}
pub fn count(self: Self) usize {
return self.data.count();
}
pub const Iterator = HeaderList.Iterator;
pub fn iterator(self: Self) Iterator {
return self.data.iterator();
pub fn toSlice(self: Self) []const HeaderEntry {
return self.data.toSliceConst();
}
pub fn append(self: *Self, name: []const u8, value: []const u8, never_index: ?bool) !void {
const n = self.data.count() + 1;
const n = self.data.len + 1;
try self.data.ensureCapacity(n);
var entry: HeaderEntry = undefined;
if (self.index.get(name)) |kv| {
@ -190,7 +182,7 @@ pub const Headers = struct {
pub fn upsert(self: *Self, name: []const u8, value: []const u8, never_index: ?bool) !void {
if (self.index.get(name)) |kv| {
const dex = kv.value;
if (dex.count() != 1)
if (dex.len != 1)
return error.CannotUpsertMultiValuedField;
var e = &self.data.at(dex.at(0));
try e.modify(value, never_index);
@ -209,7 +201,7 @@ pub const Headers = struct {
if (self.index.remove(name)) |kv| {
var dex = &kv.value;
// iterate backwards
var i = dex.count();
var i = dex.len;
while (i > 0) {
i -= 1;
const data_index = dex.at(i);
@ -232,18 +224,18 @@ pub const Headers = struct {
const removed = self.data.orderedRemove(i);
const kv = self.index.get(removed.name).?;
var dex = &kv.value;
if (dex.count() == 1) {
if (dex.len == 1) {
// was last item; delete the index
_ = self.index.remove(kv.key);
dex.deinit();
removed.deinit();
self.allocator.free(kv.key);
} else {
dex.shrink(dex.count() - 1);
dex.shrink(dex.len - 1);
removed.deinit();
}
// if it was the last item; no need to rebuild index
if (i != self.data.count()) {
if (i != self.data.len) {
self.rebuild_index();
}
}
@ -254,18 +246,18 @@ pub const Headers = struct {
const removed = self.data.swapRemove(i);
const kv = self.index.get(removed.name).?;
var dex = &kv.value;
if (dex.count() == 1) {
if (dex.len == 1) {
// was last item; delete the index
_ = self.index.remove(kv.key);
dex.deinit();
removed.deinit();
self.allocator.free(kv.key);
} else {
dex.shrink(dex.count() - 1);
dex.shrink(dex.len - 1);
removed.deinit();
}
// if it was the last item; no need to rebuild index
if (i != self.data.count()) {
if (i != self.data.len) {
self.rebuild_index();
}
}
@ -289,10 +281,9 @@ pub const Headers = struct {
pub fn get(self: Self, allocator: *Allocator, name: []const u8) !?[]const HeaderEntry {
const dex = self.getIndices(name) orelse return null;
const buf = try allocator.alloc(HeaderEntry, dex.count());
var it = dex.iterator();
const buf = try allocator.alloc(HeaderEntry, dex.len);
var n: usize = 0;
while (it.next()) |idx| {
for (dex.toSliceConst()) |idx| {
buf[n] = self.data.at(idx);
n += 1;
}
@ -314,9 +305,8 @@ pub const Headers = struct {
// adapted from mem.join
const total_len = blk: {
var sum: usize = dex.count() - 1; // space for separator(s)
var it = dex.iterator();
while (it.next()) |idx|
var sum: usize = dex.len - 1; // space for separator(s)
for (dex.toSliceConst()) |idx|
sum += self.data.at(idx).value.len;
break :blk sum;
};
@ -348,10 +338,9 @@ pub const Headers = struct {
}
}
{ // fill up indexes again; we know capacity is fine from before
var it = self.data.iterator();
while (it.next()) |entry| {
for (self.data.toSliceConst()) |entry, i| {
var dex = &self.index.get(entry.name).?.value;
dex.appendAssumeCapacity(it.count);
dex.appendAssumeCapacity(i);
}
}
}
@ -369,8 +358,7 @@ pub const Headers = struct {
comptime Errors: type,
output: fn (@TypeOf(context), []const u8) Errors!void,
) Errors!void {
var it = self.iterator();
while (it.next()) |entry| {
for (self.toSlice()) |entry| {
try output(context, entry.name);
try output(context, ": ");
try output(context, entry.value);
@ -386,8 +374,7 @@ test "Headers.iterator" {
try h.append("cookie", "somevalue", null);
var count: i32 = 0;
var it = h.iterator();
while (it.next()) |e| {
for (h.toSlice()) |e| {
if (count == 0) {
testing.expectEqualSlices(u8, "foo", e.name);
testing.expectEqualSlices(u8, "bar", e.value);
@ -420,10 +407,10 @@ test "Headers.delete" {
try h.append("cookie", "somevalue", null);
testing.expectEqual(false, h.delete("not-present"));
testing.expectEqual(@as(usize, 3), h.count());
testing.expectEqual(@as(usize, 3), h.toSlice().len);
testing.expectEqual(true, h.delete("foo"));
testing.expectEqual(@as(usize, 2), h.count());
testing.expectEqual(@as(usize, 2), h.toSlice().len);
{
const e = h.at(0);
testing.expectEqualSlices(u8, "baz", e.name);
@ -448,7 +435,7 @@ test "Headers.orderedRemove" {
try h.append("cookie", "somevalue", null);
h.orderedRemove(0);
testing.expectEqual(@as(usize, 2), h.count());
testing.expectEqual(@as(usize, 2), h.toSlice().len);
{
const e = h.at(0);
testing.expectEqualSlices(u8, "baz", e.name);
@ -471,7 +458,7 @@ test "Headers.swapRemove" {
try h.append("cookie", "somevalue", null);
h.swapRemove(0);
testing.expectEqual(@as(usize, 2), h.count());
testing.expectEqual(@as(usize, 2), h.toSlice().len);
{
const e = h.at(0);
testing.expectEqualSlices(u8, "cookie", e.name);