authorgravatar for saurabh.m@proton.meSaurabh Mishra <saurabh.m@proton.me> 2026-05-02 02:26:15+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-05-02 02:26:15+02:00
logd02d0b879c143e1495fc360845d6feec1ac293ed
treec0f3ccc7356862d19ab4d10f98e6c57404ed25e6
parent845b6a8efe5ac71c9df02373fe3716814cb7b92d

`std:ArrayList`: Merge `getLastOrNull` into `getLast` (#32008)

This PR merges the functionality of the `getLastOrNull` method into `getLast`, which improves consistency as its based on methods like `front`, `back`, and `peek` in the `Deque` and `PriorityQueue` containers. Reviewed-on: https://codeberg.org/ziglang/zig/pulls/32008 Reviewed-by: Andrew Kelley <andrew@ziglang.org>

11 files changed, 39 insertions(+), 60 deletions(-)

lib/compiler/build_runner.zig+1-1
......@@ -1397,7 +1397,7 @@ fn makeStep(
13971397 defer run.max_rss_mutex.unlock(io);
13981398 run.available_rss += s.max_rss;
13991399 dispatch_set.ensureUnusedCapacity(gpa, run.memory_blocked_steps.items.len) catch @panic("OOM");
1400 while (run.memory_blocked_steps.getLastOrNull()) |candidate| {
1400 while (run.memory_blocked_steps.getLast()) |candidate| {
14011401 if (run.available_rss < candidate.max_rss) break;
14021402 assert(run.memory_blocked_steps.pop() == candidate);
14031403 dispatch_set.appendAssumeCapacity(candidate);
lib/compiler/translate-c/MacroTranslator.zig+1-1
......@@ -361,7 +361,7 @@ fn parseCNumLit(mt: *MacroTranslator) ParseError!ZigNode {
361361 return error.ParseError;
362362 },
363363 });
364 if (bytes.getLast() == '.') {
364 if (bytes.getLast().? == '.') {
365365 bytes.appendAssumeCapacity('0');
366366 } else if (mem.findAny(u8, bytes.items, ".eEpP") == null) {
367367 bytes.appendSliceAssumeCapacity(".0");
lib/docs/wasm/markdown/Parser.zig+11-11
......@@ -209,7 +209,7 @@ pub fn feedLine(p: *Parser, line: []const u8) Allocator.Error!void {
209209 } else p.pending_blocks.items.len;
210210
211211 const in_code_block = p.pending_blocks.items.len > 0 and
212 p.pending_blocks.getLast().tag == .code_block;
212 p.pending_blocks.getLast().?.tag == .code_block;
213213 const code_block_end = in_code_block and
214214 first_unmatched + 1 == p.pending_blocks.items.len;
215215 // New blocks cannot be started if we are actively inside a code block or
......@@ -225,7 +225,7 @@ pub fn feedLine(p: *Parser, line: []const u8) Allocator.Error!void {
225225 if (maybe_block_start == null and
226226 !isBlank(rest_line) and
227227 p.pending_blocks.items.len > 0 and
228 p.pending_blocks.getLast().tag == .paragraph)
228 p.pending_blocks.getLast().?.tag == .paragraph)
229229 {
230230 try p.addScratchStringLine(mem.trimStart(u8, rest_line, " \t"));
231231 return;
......@@ -236,7 +236,7 @@ pub fn feedLine(p: *Parser, line: []const u8) Allocator.Error!void {
236236 // paragraphs.
237237 if (maybe_block_start != null and
238238 p.pending_blocks.items.len > 0 and
239 p.pending_blocks.getLast().tag == .paragraph)
239 p.pending_blocks.getLast().?.tag == .paragraph)
240240 {
241241 try p.closeLastBlock();
242242 }
......@@ -259,7 +259,7 @@ pub fn feedLine(p: *Parser, line: []const u8) Allocator.Error!void {
259259 // Do not append the end of a code block (```) as textual content.
260260 if (code_block_end) return;
261261
262 const can_accept = if (p.pending_blocks.getLastOrNull()) |last_pending_block|
262 const can_accept = if (p.pending_blocks.getLast()) |last_pending_block|
263263 last_pending_block.canAccept()
264264 else
265265 .blocks;
......@@ -273,7 +273,7 @@ pub fn feedLine(p: *Parser, line: []const u8) Allocator.Error!void {
273273 // loose, since we might just be looking at a blank line after the
274274 // end of the last item in the list. The final determination will be
275275 // made when appending the next child of the list or list item.
276 const maybe_containing_list_index = if (p.pending_blocks.items.len > 0 and p.pending_blocks.getLast().tag == .list_item)
276 const maybe_containing_list_index = if (p.pending_blocks.items.len > 0 and p.pending_blocks.getLast().?.tag == .list_item)
277277 p.pending_blocks.items.len - 2
278278 else
279279 null;
......@@ -368,7 +368,7 @@ const BlockStart = struct {
368368};
369369
370370fn appendBlockStart(p: *Parser, block_start: BlockStart) !void {
371 if (p.pending_blocks.getLastOrNull()) |last_pending_block| {
371 if (p.pending_blocks.getLast()) |last_pending_block| {
372372 // Close the last block if it is a list and the new block is not a list item
373373 // or not of the same marker type.
374374 const should_close_list = last_pending_block.tag == .list and
......@@ -383,7 +383,7 @@ fn appendBlockStart(p: *Parser, block_start: BlockStart) !void {
383383 }
384384 }
385385
386 if (p.pending_blocks.getLastOrNull()) |last_pending_block| {
386 if (p.pending_blocks.getLast()) |last_pending_block| {
387387 // If the last block is a list or list item, check for tightness based
388388 // on the last line.
389389 const maybe_containing_list = switch (last_pending_block.tag) {
......@@ -401,7 +401,7 @@ fn appendBlockStart(p: *Parser, block_start: BlockStart) !void {
401401 // Start a new list if the new block is a list item and there is no
402402 // containing list yet.
403403 if (block_start.tag == .list_item and
404 (p.pending_blocks.items.len == 0 or p.pending_blocks.getLast().tag != .list))
404 (p.pending_blocks.items.len == 0 or p.pending_blocks.getLast().?.tag != .list))
405405 {
406406 try p.pending_blocks.append(p.allocator, .{
407407 .tag = .list,
......@@ -417,7 +417,7 @@ fn appendBlockStart(p: *Parser, block_start: BlockStart) !void {
417417
418418 if (block_start.tag == .table_row) {
419419 // Likewise, table rows start a table implicitly.
420 if (p.pending_blocks.items.len == 0 or p.pending_blocks.getLast().tag != .table) {
420 if (p.pending_blocks.items.len == 0 or p.pending_blocks.getLast().?.tag != .table) {
421421 try p.pending_blocks.append(p.allocator, .{
422422 .tag = .table,
423423 .data = .{ .table = .{
......@@ -429,7 +429,7 @@ fn appendBlockStart(p: *Parser, block_start: BlockStart) !void {
429429 });
430430 }
431431
432 const current_row = p.scratch_extra.items.len - p.pending_blocks.getLast().extra_start;
432 const current_row = p.scratch_extra.items.len - p.pending_blocks.getLast().?.extra_start;
433433 if (current_row <= 1) {
434434 var buffer: [max_table_columns]Node.TableCellAlignment = undefined;
435435 const table_row = &block_start.data.table_row;
......@@ -441,7 +441,7 @@ fn appendBlockStart(p: *Parser, block_start: BlockStart) !void {
441441 // We need to go back and mark the header row and its column
442442 // alignments.
443443 const datas = p.nodes.items(.data);
444 const header_data = datas[p.scratch_extra.getLast()];
444 const header_data = datas[p.scratch_extra.getLast().?];
445445 for (p.extraChildren(header_data.container.children), 0..) |header_cell, i| {
446446 const alignment = if (i < alignments.len) alignments[i] else .unset;
447447 const cell_data = &datas[@intFromEnum(header_cell)].table_cell;
lib/std/array_list.zig+10-31
......@@ -544,16 +544,13 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type
544544 return self.allocatedSlice()[self.items.len..];
545545 }
546546
547 /// Returns the last element from the list.
548 /// Asserts that the list is not empty.
549 pub fn getLast(self: Self) T {
550 return self.items[self.items.len - 1];
551 }
547 /// Deprecated in favor of `getLast`
548 pub const getLastOrNull = getLast;
552549
553 /// Returns the last element from the list, or `null` if list is empty.
554 pub fn getLastOrNull(self: Self) ?T {
550 /// Returns the last element from the list, or `null` if the list is empty.
551 pub fn getLast(self: Self) ?T {
555552 if (self.items.len == 0) return null;
556 return self.getLast();
553 return self.items[self.items.len - 1];
557554 }
558555 };
559556}
......@@ -1394,17 +1391,10 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
13941391 return self.allocatedSlice()[self.items.len..];
13951392 }
13961393
1397 /// Return the last element from the list.
1398 /// Asserts that the list is not empty.
1399 pub fn getLast(self: Self) T {
1400 return self.items[self.items.len - 1];
1401 }
1402
1403 /// Return the last element from the list, or
1404 /// return `null` if list is empty.
1405 pub fn getLastOrNull(self: Self) ?T {
1394 /// Returns the last element from the list, or `null` if the list is empty.
1395 pub fn getLast(self: Self) ?T {
14061396 if (self.items.len == 0) return null;
1407 return self.getLast();
1397 return self.items[self.items.len - 1];
14081398 }
14091399
14101400 /// Called when memory growth is necessary. Returns a capacity larger than
......@@ -2394,22 +2384,11 @@ test "Managed(u32).getLast()" {
23942384 var list = Managed(u32).init(a);
23952385 defer list.deinit();
23962386
2397 try list.append(2);
2398 const const_list = list;
2399 try testing.expectEqual(const_list.getLast(), 2);
2400}
2401
2402test "Managed(u32).getLastOrNull()" {
2403 const a = testing.allocator;
2404
2405 var list = Managed(u32).init(a);
2406 defer list.deinit();
2407
2408 try testing.expectEqual(list.getLastOrNull(), null);
2387 try testing.expectEqual(list.getLast(), null);
24092388
24102389 try list.append(2);
24112390 const const_list = list;
2412 try testing.expectEqual(const_list.getLastOrNull().?, 2);
2391 try testing.expectEqual(const_list.getLast().?, 2);
24132392}
24142393
24152394test "return OutOfMemory when capacity would exceed maximum usize integer value" {
lib/std/deque.zig+1-1
......@@ -696,7 +696,7 @@ fn fuzzAgainstArrayList(_: void, smith: *std.testing.Smith) anyerror!void {
696696 try q.ensureTotalCapacityPrecise(q_gpa, q.len + growth);
697697 },
698698 }
699 try testing.expectEqual(l.getLastOrNull(), q.back());
699 try testing.expectEqual(l.getLast(), q.back());
700700 try testing.expectEqual(
701701 if (l.items.len > 0) l.items[0] else null,
702702 q.front(),
lib/std/zig/Ast/Render.zig+2-2
......@@ -3442,7 +3442,7 @@ const AutoIndentingStream = struct {
34423442 /// Sets current indentation level to be the same as that of the last pushSpace.
34433443 pub fn enableSpaceMode(ais: *AutoIndentingStream, space: Space) void {
34443444 if (ais.space_stack.items.len == 0) return;
3445 const curr = ais.space_stack.getLast();
3445 const curr = ais.space_stack.getLast().?;
34463446 if (curr.space != space) return;
34473447 ais.space_mode = curr.indent_count;
34483448 }
......@@ -3453,7 +3453,7 @@ const AutoIndentingStream = struct {
34533453
34543454 pub fn lastSpaceModeIndent(ais: *AutoIndentingStream) usize {
34553455 if (ais.space_stack.items.len == 0) return 0;
3456 return ais.space_stack.getLast().indent_count * ais.indent_delta;
3456 return ais.space_stack.getLast().?.indent_count * ais.indent_delta;
34573457 }
34583458
34593459 /// Push default indentation
lib/std/zig/WindowsSdk.zig+4-4
......@@ -891,7 +891,7 @@ const MsvcLibDir = struct {
891891
892892 lib_dir_buf.appendSliceAssumeCapacity(installation_path);
893893
894 if (!Dir.path.isSep(lib_dir_buf.getLast())) {
894 if (!Dir.path.isSep(lib_dir_buf.getLast().?)) {
895895 try lib_dir_buf.append('\\');
896896 }
897897 const installation_path_with_trailing_sep_len = lib_dir_buf.items.len;
......@@ -1064,7 +1064,7 @@ const MsvcLibDir = struct {
10641064 errdefer msvc_dir.deinit();
10651065
10661066 // String might contain trailing slash, so trim it here
1067 if (msvc_dir.items.len > "C:\\".len and msvc_dir.getLast() == '\\') _ = msvc_dir.pop();
1067 if (msvc_dir.items.len > "C:\\".len and msvc_dir.getLast().? == '\\') _ = msvc_dir.pop();
10681068
10691069 // Remove `\include` at the end of path
10701070 if (std.mem.endsWith(u8, msvc_dir.items, "\\include")) {
......@@ -1108,7 +1108,7 @@ const MsvcLibDir = struct {
11081108
11091109 try list.appendSlice(VS140COMNTOOLS); // C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\Tools
11101110 // String might contain trailing slash, so trim it here
1111 if (list.items.len > "C:\\".len and list.getLast() == '\\') _ = list.pop();
1111 if (list.items.len > "C:\\".len and list.getLast().? == '\\') _ = list.pop();
11121112 list.shrinkRetainingCapacity(list.items.len - "\\Common7\\Tools".len); // C:\Program Files (x86)\Microsoft Visual Studio 14.0
11131113 break :base_path list;
11141114 }
......@@ -1131,7 +1131,7 @@ const MsvcLibDir = struct {
11311131 errdefer path.deinit();
11321132
11331133 // String might contain trailing slash, so trim it here
1134 if (path.items.len > "C:\\".len and path.getLast() == '\\') _ = path.pop();
1134 if (path.items.len > "C:\\".len and path.getLast().? == '\\') _ = path.pop();
11351135 break :base_path path;
11361136 }
11371137 return error.PathNotFound;
lib/std/zig/llvm/Builder.zig+4-4
......@@ -2310,7 +2310,7 @@ pub fn trailingStrtabString(self: *Builder) Allocator.Error!StrtabString {
23102310}
23112311
23122312pub fn trailingStrtabStringAssumeCapacity(self: *Builder) StrtabString {
2313 const start = self.strtab_string_indices.getLast();
2313 const start = self.strtab_string_indices.getLast().?;
23142314 const bytes: []const u8 = self.strtab_string_bytes.items[start..];
23152315 const gop = self.strtab_string_map.getOrPutAssumeCapacityAdapted(bytes, StrtabString.Adapter{ .builder = self });
23162316 if (gop.found_existing) {
......@@ -8905,7 +8905,7 @@ pub fn deinit(self: *Builder) void {
89058905
89068906pub fn finishModuleAsm(self: *Builder, aw: *Writer.Allocating) Allocator.Error!void {
89078907 self.module_asm = aw.toArrayList();
8908 if (self.module_asm.getLastOrNull()) |last| if (last != '\n')
8908 if (self.module_asm.getLast()) |last| if (last != '\n')
89098909 try self.module_asm.append(self.gpa, '\n');
89108910}
89118911
......@@ -8951,7 +8951,7 @@ pub fn trailingString(self: *Builder) Allocator.Error!String {
89518951}
89528952
89538953pub fn trailingStringAssumeCapacity(self: *Builder) String {
8954 const start = self.string_indices.getLast();
8954 const start = self.string_indices.getLast().?;
89558955 const bytes: []const u8 = self.string_bytes.items[start..];
89568956 const gop = self.string_map.getOrPutAssumeCapacityAdapted(bytes, String.Adapter{ .builder = self });
89578957 if (gop.found_existing) {
......@@ -12150,7 +12150,7 @@ pub fn trailingMetadataString(self: *Builder) Allocator.Error!Metadata.String {
1215012150}
1215112151
1215212152pub fn trailingMetadataStringAssumeCapacity(self: *Builder) Metadata.String {
12153 const start = self.metadata_string_indices.getLast();
12153 const start = self.metadata_string_indices.getLast().?;
1215412154 const bytes: []const u8 = self.metadata_string_bytes.items[start..];
1215512155 assert(bytes.len > 0);
1215612156 const gop = self.metadata_string_map.getOrPutAssumeCapacityAdapted(bytes, Metadata.String.Adapter{ .builder = self });
src/codegen/llvm.zig+1-1
......@@ -747,7 +747,7 @@ pub const Object = struct {
747747 b.module_asm.appendSliceAssumeCapacity(assembly);
748748 b.module_asm.appendAssumeCapacity('\n');
749749 }
750 if (b.module_asm.getLastOrNull()) |last| {
750 if (b.module_asm.getLast()) |last| {
751751 if (last != '\n') try b.module_asm.append(gpa, '\n');
752752 }
753753 }
src/codegen/spirv/CodeGen.zig+2-2
......@@ -4829,7 +4829,7 @@ fn structuredBreak(cg: *CodeGen, target_block: Id) !void {
48294829 assert(cg.control_flow == .structured);
48304830
48314831 const gpa = cg.module.gpa;
4832 const sblock = cg.control_flow.structured.block_stack.getLast();
4832 const sblock = cg.control_flow.structured.block_stack.getLast().?;
48334833 const merge_block = switch (sblock.*) {
48344834 .selection => |*merge| blk: {
48354835 const merge_label = cg.module.allocId();
......@@ -5044,7 +5044,7 @@ fn lowerBlock(cg: *CodeGen, inst: Air.Inst.Index, body: []const Air.Inst.Index)
50445044 .operand_2 = this_block,
50455045 });
50465046
5047 const sblock = cf.block_stack.getLast();
5047 const sblock = cf.block_stack.getLast().?;
50485048
50495049 if (ty.isNoReturn(zcu)) {
50505050 // If this block is noreturn, this instruction is the last of a block,
src/codegen/x86_64/CodeGen.zig+2-2
......@@ -2065,7 +2065,7 @@ fn gen(
20652065
20662066 const epilogue = if (self.epilogue_relocs.items.len > 0) epilogue: {
20672067 var last_inst: Mir.Inst.Index = @intCast(self.mir_instructions.len - 1);
2068 while (self.epilogue_relocs.getLastOrNull() == last_inst) {
2068 while (self.epilogue_relocs.getLast() == last_inst) {
20692069 self.epilogue_relocs.items.len -= 1;
20702070 self.mir_instructions.set(last_inst, .{
20712071 .tag = .pseudo,
......@@ -176545,7 +176545,7 @@ fn lowerBlock(self: *CodeGen, inst: Air.Inst.Index, body: []const Air.Inst.Index
176545176545 defer block_data.value.deinit(self.gpa);
176546176546 if (block_data.value.relocs.items.len > 0) {
176547176547 var last_inst: Mir.Inst.Index = @intCast(self.mir_instructions.len - 1);
176548 while (block_data.value.relocs.getLastOrNull() == last_inst) {
176548 while (block_data.value.relocs.getLast() == last_inst) {
176549176549 block_data.value.relocs.items.len -= 1;
176550176550 self.mir_instructions.set(last_inst, .{
176551176551 .tag = .pseudo,