Skip to content

Commit fd16288

Browse files
zbanksandrewrk
authored andcommitted
std/ArrayList: Allow ArrayList(u0) to be created
Enable creating ArrayList with zero-sized types. This type still tracks length, but does not allocate additional memory.
1 parent 8028e46 commit fd16288

File tree

1 file changed

+56
-21
lines changed

1 file changed

+56
-21
lines changed

lib/std/array_list.zig

Lines changed: 56 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -65,16 +65,23 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
6565
pub fn initCapacity(allocator: *Allocator, num: usize) !Self {
6666
var self = Self.init(allocator);
6767

68-
const new_memory = try self.allocator.allocAdvanced(T, alignment, num, .at_least);
69-
self.items.ptr = new_memory.ptr;
70-
self.capacity = new_memory.len;
68+
if (@sizeOf(T) > 0) {
69+
const new_memory = try self.allocator.allocAdvanced(T, alignment, num, .at_least);
70+
self.items.ptr = new_memory.ptr;
71+
self.capacity = new_memory.len;
72+
} else {
73+
// If `T` is a zero-sized type, then we do not need to allocate memory.
74+
self.capacity = std.math.maxInt(usize);
75+
}
7176

7277
return self;
7378
}
7479

7580
/// Release all allocated memory.
7681
pub fn deinit(self: Self) void {
77-
self.allocator.free(self.allocatedSlice());
82+
if (@sizeOf(T) > 0) {
83+
self.allocator.free(self.allocatedSlice());
84+
}
7885
}
7986

8087
pub const span = @compileError("deprecated: use `items` field directly");
@@ -279,13 +286,17 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
279286
pub fn shrinkAndFree(self: *Self, new_len: usize) void {
280287
assert(new_len <= self.items.len);
281288

282-
self.items = self.allocator.realloc(self.allocatedSlice(), new_len) catch |e| switch (e) {
283-
error.OutOfMemory => { // no problem, capacity is still correct then.
284-
self.items.len = new_len;
285-
return;
286-
},
287-
};
288-
self.capacity = new_len;
289+
if (@sizeOf(T) > 0) {
290+
self.items = self.allocator.realloc(self.allocatedSlice(), new_len) catch |e| switch (e) {
291+
error.OutOfMemory => { // no problem, capacity is still correct then.
292+
self.items.len = new_len;
293+
return;
294+
},
295+
};
296+
self.capacity = new_len;
297+
} else {
298+
self.items.len = new_len;
299+
}
289300
}
290301

291302
/// Reduce length to `new_len`.
@@ -313,18 +324,22 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
313324
/// Modify the array so that it can hold at least `new_capacity` items.
314325
/// Invalidates pointers if additional memory is needed.
315326
pub fn ensureTotalCapacity(self: *Self, new_capacity: usize) !void {
316-
var better_capacity = self.capacity;
317-
if (better_capacity >= new_capacity) return;
327+
if (@sizeOf(T) > 0) {
328+
var better_capacity = self.capacity;
329+
if (better_capacity >= new_capacity) return;
318330

319-
while (true) {
320-
better_capacity += better_capacity / 2 + 8;
321-
if (better_capacity >= new_capacity) break;
322-
}
331+
while (true) {
332+
better_capacity += better_capacity / 2 + 8;
333+
if (better_capacity >= new_capacity) break;
334+
}
323335

324-
// TODO This can be optimized to avoid needlessly copying undefined memory.
325-
const new_memory = try self.allocator.reallocAtLeast(self.allocatedSlice(), better_capacity);
326-
self.items.ptr = new_memory.ptr;
327-
self.capacity = new_memory.len;
336+
// TODO This can be optimized to avoid needlessly copying undefined memory.
337+
const new_memory = try self.allocator.reallocAtLeast(self.allocatedSlice(), better_capacity);
338+
self.items.ptr = new_memory.ptr;
339+
self.capacity = new_memory.len;
340+
} else {
341+
self.capacity = std.math.maxInt(usize);
342+
}
328343
}
329344

330345
/// Modify the array so that it can hold at least `additional_count` **more** items.
@@ -1299,3 +1314,23 @@ test "ArrayListAligned/ArrayListAlignedUnmanaged accepts unaligned slices" {
12991314
try testing.expectEqualSlices(u8, list.items, &.{ 0, 8, 9, 6, 7, 2, 3 });
13001315
}
13011316
}
1317+
1318+
test "std.ArrayList(u0)" {
1319+
// An ArrayList on zero-sized types should not need to allocate
1320+
const a = &testing.FailingAllocator.init(testing.allocator, 0).allocator;
1321+
1322+
var list = ArrayList(u0).init(a);
1323+
defer list.deinit();
1324+
1325+
try list.append(0);
1326+
try list.append(0);
1327+
try list.append(0);
1328+
try testing.expectEqual(list.items.len, 3);
1329+
1330+
var count: usize = 0;
1331+
for (list.items) |x| {
1332+
try testing.expectEqual(x, 0);
1333+
count += 1;
1334+
}
1335+
try testing.expectEqual(count, 3);
1336+
}

0 commit comments

Comments
 (0)