| ... | @@ -65,16 +65,23 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -65,16 +65,23 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 65 | pub fn initCapacity(allocator: *Allocator, num: usize) !Self { | 65 | pub fn initCapacity(allocator: *Allocator, num: usize) !Self { |
| 66 | var self = Self.init(allocator); | 66 | var self = Self.init(allocator); |
| 67 | | 67 | |
| 68 | const new_memory = try self.allocator.allocAdvanced(T, alignment, num, .at_least); | 68 | if (@sizeOf(T) > 0) { |
| 69 | self.items.ptr = new_memory.ptr; | 69 | const new_memory = try self.allocator.allocAdvanced(T, alignment, num, .at_least); |
| 70 | self.capacity = new_memory.len; | 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 | } |
| 71 | | 76 | |
| 72 | return self; | 77 | return self; |
| 73 | } | 78 | } |
| 74 | | 79 | |
| 75 | /// Release all allocated memory. | 80 | /// Release all allocated memory. |
| 76 | pub fn deinit(self: Self) void { | 81 | pub fn deinit(self: Self) void { |
| 77 | self.allocator.free(self.allocatedSlice()); | 82 | if (@sizeOf(T) > 0) { |
| | 83 | self.allocator.free(self.allocatedSlice()); |
| | 84 | } |
| 78 | } | 85 | } |
| 79 | | 86 | |
| 80 | pub const span = @compileError("deprecated: use `items` field directly"); | 87 | pub const span = @compileError("deprecated: use `items` field directly"); |
| ... | @@ -279,13 +286,17 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -279,13 +286,17 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 279 | pub fn shrinkAndFree(self: *Self, new_len: usize) void { | 286 | pub fn shrinkAndFree(self: *Self, new_len: usize) void { |
| 280 | assert(new_len <= self.items.len); | 287 | assert(new_len <= self.items.len); |
| 281 | | 288 | |
| 282 | self.items = self.allocator.realloc(self.allocatedSlice(), new_len) catch |e| switch (e) { | 289 | if (@sizeOf(T) > 0) { |
| 283 | error.OutOfMemory => { // no problem, capacity is still correct then. | 290 | self.items = self.allocator.realloc(self.allocatedSlice(), new_len) catch |e| switch (e) { |
| 284 | self.items.len = new_len; | 291 | error.OutOfMemory => { // no problem, capacity is still correct then. |
| 285 | return; | 292 | self.items.len = new_len; |
| 286 | }, | 293 | return; |
| 287 | }; | 294 | }, |
| 288 | self.capacity = new_len; | 295 | }; |
| | 296 | self.capacity = new_len; |
| | 297 | } else { |
| | 298 | self.items.len = new_len; |
| | 299 | } |
| 289 | } | 300 | } |
| 290 | | 301 | |
| 291 | /// Reduce length to `new_len`. | 302 | /// Reduce length to `new_len`. |
| ... | @@ -313,18 +324,22 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -313,18 +324,22 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 313 | /// Modify the array so that it can hold at least `new_capacity` items. | 324 | /// Modify the array so that it can hold at least `new_capacity` items. |
| 314 | /// Invalidates pointers if additional memory is needed. | 325 | /// Invalidates pointers if additional memory is needed. |
| 315 | pub fn ensureTotalCapacity(self: *Self, new_capacity: usize) !void { | 326 | pub fn ensureTotalCapacity(self: *Self, new_capacity: usize) !void { |
| 316 | var better_capacity = self.capacity; | 327 | if (@sizeOf(T) > 0) { |
| 317 | if (better_capacity >= new_capacity) return; | 328 | var better_capacity = self.capacity; |
| | 329 | if (better_capacity >= new_capacity) return; |
| 318 | | 330 | |
| 319 | while (true) { | 331 | while (true) { |
| 320 | better_capacity += better_capacity / 2 + 8; | 332 | better_capacity += better_capacity / 2 + 8; |
| 321 | if (better_capacity >= new_capacity) break; | 333 | if (better_capacity >= new_capacity) break; |
| 322 | } | 334 | } |
| 323 | | 335 | |
| 324 | // TODO This can be optimized to avoid needlessly copying undefined memory. | 336 | // TODO This can be optimized to avoid needlessly copying undefined memory. |
| 325 | const new_memory = try self.allocator.reallocAtLeast(self.allocatedSlice(), better_capacity); | 337 | const new_memory = try self.allocator.reallocAtLeast(self.allocatedSlice(), better_capacity); |
| 326 | self.items.ptr = new_memory.ptr; | 338 | self.items.ptr = new_memory.ptr; |
| 327 | self.capacity = new_memory.len; | 339 | self.capacity = new_memory.len; |
| | 340 | } else { |
| | 341 | self.capacity = std.math.maxInt(usize); |
| | 342 | } |
| 328 | } | 343 | } |
| 329 | | 344 | |
| 330 | /// Modify the array so that it can hold at least `additional_count` **more** items. | 345 | /// Modify the array so that it can hold at least `additional_count` **more** items. |
| ... | @@ -1299,3 +1314,23 @@ test "ArrayListAligned/ArrayListAlignedUnmanaged accepts unaligned slices" { | ... | @@ -1299,3 +1314,23 @@ test "ArrayListAligned/ArrayListAlignedUnmanaged accepts unaligned slices" { |
| 1299 | try testing.expectEqualSlices(u8, list.items, &.{ 0, 8, 9, 6, 7, 2, 3 }); | 1314 | try testing.expectEqualSlices(u8, list.items, &.{ 0, 8, 9, 6, 7, 2, 3 }); |
| 1300 | } | 1315 | } |
| 1301 | } | 1316 | } |
| | 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 | } |