authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-09-21 04:55:39-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2025-09-21 04:55:39-07:00
log594cb38fcb6c2edccee6b2fd74adec81b3be547a
treec8a29f062fac286cfef622737affaaadc4ff4d73
parent010d9a63f20d8a4bd14cff0ada690b2d127a0371
parent3cc0fc601af62adebf6b9f3bb1a241fa8a501d0b
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #25302 from ziglang/growCapacity

std: remove loop from growCapacity

6 files changed, 18 insertions(+), 67 deletions(-)

lib/std/Io/Writer.zig+1-1
......@@ -2667,7 +2667,7 @@ pub const Allocating = struct {
26672667 pub fn ensureTotalCapacity(a: *Allocating, new_capacity: usize) Allocator.Error!void {
26682668 // Protects growing unnecessarily since better_capacity will be larger.
26692669 if (a.writer.buffer.len >= new_capacity) return;
2670 const better_capacity = ArrayList(u8).growCapacity(a.writer.buffer.len, new_capacity);
2670 const better_capacity = ArrayList(u8).growCapacity(new_capacity);
26712671 return ensureTotalCapacityPrecise(a, better_capacity);
26722672 }
26732673
lib/std/array_list.zig+6-11
......@@ -172,7 +172,7 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type
172172 // a new buffer and doing our own copy. With a realloc() call,
173173 // the allocator implementation would pointlessly copy our
174174 // extra capacity.
175 const new_capacity = Aligned(T, alignment).growCapacity(self.capacity, new_len);
175 const new_capacity = Aligned(T, alignment).growCapacity(new_len);
176176 const old_memory = self.allocatedSlice();
177177 if (self.allocator.remap(old_memory, new_capacity)) |new_memory| {
178178 self.items.ptr = new_memory.ptr;
......@@ -408,7 +408,7 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type
408408 // Protects growing unnecessarily since better_capacity will be larger.
409409 if (self.capacity >= new_capacity) return;
410410
411 const better_capacity = Aligned(T, alignment).growCapacity(self.capacity, new_capacity);
411 const better_capacity = Aligned(T, alignment).growCapacity(new_capacity);
412412 return self.ensureTotalCapacityPrecise(better_capacity);
413413 }
414414
......@@ -1160,7 +1160,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
11601160 /// Invalidates element pointers if additional memory is needed.
11611161 pub fn ensureTotalCapacity(self: *Self, gpa: Allocator, new_capacity: usize) Allocator.Error!void {
11621162 if (self.capacity >= new_capacity) return;
1163 return self.ensureTotalCapacityPrecise(gpa, growCapacity(self.capacity, new_capacity));
1163 return self.ensureTotalCapacityPrecise(gpa, growCapacity(new_capacity));
11641164 }
11651165
11661166 /// If the current capacity is less than `new_capacity`, this function will
......@@ -1359,17 +1359,12 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
13591359 return self.getLast();
13601360 }
13611361
1362 const init_capacity = @as(comptime_int, @max(1, std.atomic.cache_line / @sizeOf(T)));
1362 const init_capacity: comptime_int = @max(1, std.atomic.cache_line / @sizeOf(T));
13631363
13641364 /// Called when memory growth is necessary. Returns a capacity larger than
13651365 /// minimum that grows super-linearly.
1366 pub fn growCapacity(current: usize, minimum: usize) usize {
1367 var new = current;
1368 while (true) {
1369 new +|= new / 2 + init_capacity;
1370 if (new >= minimum)
1371 return new;
1372 }
1366 pub fn growCapacity(minimum: usize) usize {
1367 return minimum +| (minimum / 2 + init_capacity);
13731368 }
13741369 };
13751370}
lib/std/deque.zig+1-13
......@@ -56,7 +56,7 @@ pub fn Deque(comptime T: type) type {
5656 /// Invalidates element pointers if additional memory is needed.
5757 pub fn ensureTotalCapacity(deque: *Self, gpa: Allocator, new_capacity: usize) Allocator.Error!void {
5858 if (deque.buffer.len >= new_capacity) return;
59 return deque.ensureTotalCapacityPrecise(gpa, growCapacity(deque.buffer.len, new_capacity));
59 return deque.ensureTotalCapacityPrecise(gpa, std.ArrayList(T).growCapacity(new_capacity));
6060 }
6161
6262 /// If the current capacity is less than `new_capacity`, this function will
......@@ -243,18 +243,6 @@ pub fn Deque(comptime T: type) type {
243243 return index - head_len;
244244 }
245245 }
246
247 const init_capacity: comptime_int = @max(1, std.atomic.cache_line / @sizeOf(T));
248
249 /// Called when memory growth is necessary. Returns a capacity larger than
250 /// minimum that grows super-linearly.
251 fn growCapacity(current: usize, minimum: usize) usize {
252 var new = current;
253 while (true) {
254 new +|= new / 2 + init_capacity;
255 if (new >= minimum) return new;
256 }
257 }
258246 };
259247}
260248
lib/std/json/scanner_test.zig-27
......@@ -431,33 +431,6 @@ test "skipValue" {
431431 try std.testing.expectError(error.SyntaxError, testSkipValue("[102, 111, 111}"));
432432}
433433
434fn testEnsureStackCapacity(do_ensure: bool) !void {
435 var fail_alloc = std.testing.FailingAllocator.init(std.testing.allocator, .{ .fail_index = 1 });
436 const failing_allocator = fail_alloc.allocator();
437
438 const nestings = 2049; // intentionally not a power of 2.
439 var input_string: std.ArrayListUnmanaged(u8) = .empty;
440 try input_string.appendNTimes(std.testing.allocator, '[', nestings);
441 try input_string.appendNTimes(std.testing.allocator, ']', nestings);
442 defer input_string.deinit(std.testing.allocator);
443
444 var scanner = Scanner.initCompleteInput(failing_allocator, input_string.items);
445 defer scanner.deinit();
446
447 if (do_ensure) {
448 try scanner.ensureTotalStackCapacity(nestings);
449 }
450
451 try scanner.skipValue();
452 try std.testing.expectEqual(Token.end_of_document, try scanner.next());
453}
454test "ensureTotalStackCapacity" {
455 // Once to demonstrate failure.
456 try std.testing.expectError(error.OutOfMemory, testEnsureStackCapacity(false));
457 // Then to demonstrate it works.
458 try testEnsureStackCapacity(true);
459}
460
461434fn testDiagnosticsFromSource(expected_error: ?anyerror, line: u64, col: u64, byte_offset: u64, source: anytype) !void {
462435 var diagnostics = Diagnostics{};
463436 source.enableDiagnostics(&diagnostics);
lib/std/json/static_test.zig+1-1
......@@ -914,7 +914,7 @@ test "parse at comptime" {
914914 uptime: u64,
915915 };
916916 const config = comptime x: {
917 var buf: [256]u8 = undefined;
917 var buf: [300]u8 = undefined;
918918 var fba = std.heap.FixedBufferAllocator.init(&buf);
919919 const res = parseFromSliceLeaky(Config, fba.allocator(), doc, .{});
920920 // Assert no error can occur since we are
lib/std/multi_array_list.zig+9-14
......@@ -457,24 +457,19 @@ pub fn MultiArrayList(comptime T: type) type {
457457 /// Invalidates element pointers if additional memory is needed.
458458 pub fn ensureTotalCapacity(self: *Self, gpa: Allocator, new_capacity: usize) Allocator.Error!void {
459459 if (self.capacity >= new_capacity) return;
460 return self.setCapacity(gpa, growCapacity(self.capacity, new_capacity));
460 return self.setCapacity(gpa, growCapacity(new_capacity));
461461 }
462462
463 const init_capacity = init: {
464 var max = 1;
465 for (fields) |field| max = @as(comptime_int, @max(max, @sizeOf(field.type)));
466 break :init @as(comptime_int, @max(1, std.atomic.cache_line / max));
463 const init_capacity: comptime_int = init: {
464 var max: comptime_int = 1;
465 for (fields) |field| max = @max(max, @sizeOf(field.type));
466 break :init @max(1, std.atomic.cache_line / max);
467467 };
468468
469 /// Called when memory growth is necessary. Returns a capacity larger than
470 /// minimum that grows super-linearly.
471 fn growCapacity(current: usize, minimum: usize) usize {
472 var new = current;
473 while (true) {
474 new +|= new / 2 + init_capacity;
475 if (new >= minimum)
476 return new;
477 }
469 /// Given a lower bound of required memory capacity, returns a larger value
470 /// with super-linear growth.
471 pub fn growCapacity(minimum: usize) usize {
472 return minimum +| (minimum / 2 + init_capacity);
478473 }
479474
480475 /// Modify the array so that it can hold at least `additional_count` **more** items.