ArrayList.resize()

The standard library funcrion for array list, resize leaves added elements uninitialized. So I came up with this monstrosity

behold !

pub fn array_list_resize(
	list: anytype,
	allocator: if (is_managed(@TypeOf(list))) void else std.mem.Allocator, // pass in if unamanged
	count: usize,
	value: @typeInfo(@TypeOf(list.items)).pointer.child,
) std.mem.Allocator.Error!void {
	// what ArrayList.resize() should've been
	if (is_managed(@TypeOf(list)))
		try list.ensureTotalCapacity(count)
	else
		try list.ensureTotalCapacity(allocator, count);

	@memset(list.unusedCapacitySlice(), value);
	list.items.len = count;
}

inline fn is_managed(T: type) bool {
	const L = switch (@typeInfo(T)) {
		.pointer => |p| p.child,
		else => unreachable,
	};
	return @hasField(L, "allocator");
}

that’s just AppendNTimes right?

I think there is a bug at the end, shouldn’t it be list.items.len += count?

1 Like

that’s where i got the code form, but no. this could resize things to be smaller. I did test memset on zero length arrays !

total capacity, not additional.

this is the std lib’s resize for compariosn

pub fn resize(self: *Self, gpa: Allocator, new_len: usize) Allocator.Error!void {
    try self.ensureTotalCapacity(gpa, new_len);
    self.items.len = new_len;
}

then isn’t it easier to do resize when it’s smaller and appendNTimes when it’s bigger?

not really, no.

I can see it’s a useful function, if you are using both managed and unmanaged array lists. For myself, I would just have a plain allocator param since I don’t use managed lists. Also note that the managed list will be removed from std, as far as I know.

IMO the resize method isn’t needed at all (it’s trivial), but since it does exist I think it makes sense to leave the additional items uninitialized. There are lots of ways that one could initialize the new items, so this allows for that without the penalty of double-initialization.

In languages that heavily use closures, a closure could be passed to do the initialization, but Zig is not such a language. Another approach more appropriate for Zig is to return the slice of uninitialized items, to make it easy to initialize in various ways.

the real problem with resize in the std lib is that there is no easy way to get the new elements which are now undefined. If there were, I’d just do that.

I agree that it’s not exactly trivial. That’s why I suggested a resize method that returns the slice of new elements.