authorgravatar for squeek502@hotmail.comRyan Liptak <squeek502@hotmail.com> 2021-11-01 00:38:11-07:00
committergravatar for squeek502@hotmail.comRyan Liptak <squeek502@hotmail.com> 2021-11-01 00:57:24-07:00
logf49d42729a22846ec54b6610db415ac8cdaa31db
treecfd5a54c5d1dbaed017511a740fd4f4cf5593cf9
parent83dcfd62053a80024b1cb282fddf399a36c9c58e

std.ArrayList: add ensureTotalCapacityPrecise and update doc comments

initCapacity did and still does use the ensureTotalCapacityPrecise logic because the initial capacity of an ArrayList is not important in terms of how it grows, so allocating a more exact slice up-front allows for saving memory when the array list never exceeds that initial allocation size. There are use cases where this precise capacity is useful outside of the `init` function, though, like in instances where the user does not call the `init` function themselves but otherwise knows that an ArrayList is empty so calling `ensureTotalCapacityPrecise` can give the same memory savings that `initCapacity` would have. Closes #9775

1 files changed, 30 insertions(+), 17 deletions(-)

lib/std/array_list.zig+30-17
......@@ -56,19 +56,11 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
5656 }
5757
5858 /// Initialize with capacity to hold at least `num` elements.
59 /// The resulting capacity is likely to be equal to `num`.
5960 /// Deinitialize with `deinit` or use `toOwnedSlice`.
6061 pub fn initCapacity(allocator: *Allocator, num: usize) !Self {
6162 var self = Self.init(allocator);
62
63 if (@sizeOf(T) > 0) {
64 const new_memory = try self.allocator.allocAdvanced(T, alignment, num, .at_least);
65 self.items.ptr = new_memory.ptr;
66 self.capacity = new_memory.len;
67 } else {
68 // If `T` is a zero-sized type, then we do not need to allocate memory.
69 self.capacity = std.math.maxInt(usize);
70 }
71
63 try self.ensureTotalCapacityPrecise(num);
7264 return self;
7365 }
7466
......@@ -330,8 +322,22 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
330322 if (better_capacity >= new_capacity) break;
331323 }
332324
325 return self.ensureTotalCapacityPrecise(better_capacity);
326 } else {
327 self.capacity = std.math.maxInt(usize);
328 }
329 }
330
331 /// Modify the array so that it can hold at least `new_capacity` items.
332 /// Like `ensureTotalCapacity`, but the resulting capacity is much more likely
333 /// (but not guaranteed) to be equal to `new_capacity`.
334 /// Invalidates pointers if additional memory is needed.
335 pub fn ensureTotalCapacityPrecise(self: *Self, new_capacity: usize) !void {
336 if (@sizeOf(T) > 0) {
337 if (self.capacity >= new_capacity) return;
338
333339 // TODO This can be optimized to avoid needlessly copying undefined memory.
334 const new_memory = try self.allocator.reallocAtLeast(self.allocatedSlice(), better_capacity);
340 const new_memory = try self.allocator.reallocAtLeast(self.allocatedSlice(), new_capacity);
335341 self.items.ptr = new_memory.ptr;
336342 self.capacity = new_memory.len;
337343 } else {
......@@ -464,14 +470,11 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
464470 pub const Slice = if (alignment) |a| ([]align(a) T) else []T;
465471
466472 /// Initialize with capacity to hold at least num elements.
473 /// The resulting capacity is likely to be equal to `num`.
467474 /// Deinitialize with `deinit` or use `toOwnedSlice`.
468475 pub fn initCapacity(allocator: *Allocator, num: usize) !Self {
469476 var self = Self{};
470
471 const new_memory = try allocator.allocAdvanced(T, alignment, num, .at_least);
472 self.items.ptr = new_memory.ptr;
473 self.capacity = new_memory.len;
474
477 try self.ensureTotalCapacityPrecise(allocator, num);
475478 return self;
476479 }
477480
......@@ -685,7 +688,17 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
685688 if (better_capacity >= new_capacity) break;
686689 }
687690
688 const new_memory = try allocator.reallocAtLeast(self.allocatedSlice(), better_capacity);
691 return self.ensureTotalCapacityPrecise(allocator, better_capacity);
692 }
693
694 /// Modify the array so that it can hold at least `new_capacity` items.
695 /// Like `ensureTotalCapacity`, but the resulting capacity is much more likely
696 /// (but not guaranteed) to be equal to `new_capacity`.
697 /// Invalidates pointers if additional memory is needed.
698 pub fn ensureTotalCapacityPrecise(self: *Self, allocator: *Allocator, new_capacity: usize) !void {
699 if (self.capacity >= new_capacity) return;
700
701 const new_memory = try allocator.reallocAtLeast(self.allocatedSlice(), new_capacity);
689702 self.items.ptr = new_memory.ptr;
690703 self.capacity = new_memory.len;
691704 }