authorgravatar for saurabh.m@proton.meSaurabh Mishra <saurabh.m@proton.me> 2026-08-07 07:30:10+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-08-07 07:30:10+02:00
log21f23814383ff8060a6b983c5ff9e47b5f1853ba
treeb34b8869d83fddf444d66cefd676f058118dce67
parent2b242157b875573c68e92ebe4b8dbddc7f01ffdf

std.ArrayListUnmanaged: `last` and `lastPtr` methods (#36318)

ArrayList: - `getLastOrNull` has been deprecated and renamed to `last` - `getLast` has been removed in favor of `last` combined with `.?` - `lastPtr` has been added which returns `?*T` Upgrade guide: ```zig if (list.getLastOrNull()) |foo| { // ... } const foo = list.getLast(); ``` ⬇️ ```zig if (list.last()) |foo| { // ... } const foo = list.last().?; ``` Co-authored-by: Ryan Liptak <squeek502@hotmail.com> Reviewed-on: https://codeberg.org/ziglang/zig/pulls/36318 Reviewed-by: Ryan Liptak <squeek502@noreply.codeberg.org>

12 files changed, 47 insertions(+), 38 deletions(-)

lib/compiler/Maker.zig+1-1
......@@ -2666,7 +2666,7 @@ fn makeStep(
26662666 maker.available_rss += max_rss;
26672667 dispatch_set.ensureUnusedCapacity(gpa, maker.memory_blocked_steps.items.len) catch
26682668 @panic("TODO eliminate memory allocation here");
2669 while (maker.memory_blocked_steps.getLast()) |candidate_index| {
2669 while (maker.memory_blocked_steps.last()) |candidate_index| {
26702670 const candidate_max_rss = candidate_index.ptr(c).max_rss.toBytes();
26712671 if (maker.available_rss < candidate_max_rss) break;
26722672 assert(maker.memory_blocked_steps.pop() == candidate_index);
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.last().? == '.') {
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.last().?.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.last().?.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.last().?.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.getLast()) |last_pending_block|
262 const can_accept = if (p.pending_blocks.last()) |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.last().?.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.getLast()) |last_pending_block| {
371 if (p.pending_blocks.last()) |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.getLast()) |last_pending_block| {
386 if (p.pending_blocks.last()) |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.last().?.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.last().?.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.last().?.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.last().?];
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[@backingInt(header_cell)].table_cell;
lib/std/array_list.zig+17-8
......@@ -544,14 +544,22 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type
544544 return self.allocatedSlice()[self.items.len..];
545545 }
546546
547 /// Deprecated in favor of `getLast`
548 pub const getLastOrNull = getLast;
547 /// Deprecated in favor of `last`
548 pub const getLastOrNull = last;
549549
550 /// Returns the last element from the list, or `null` if the list is empty.
551 pub fn getLast(self: Self) ?T {
550 /// Returns the last element from the list, or `null` if the list is
551 /// empty.
552 pub fn last(self: Self) ?T {
552553 if (self.items.len == 0) return null;
553554 return self.items[self.items.len - 1];
554555 }
556
557 /// Returns a pointer to the last element from the list, or `null` if
558 /// the list is empty.
559 pub fn lastPtr(self: Self) ?*T {
560 if (self.items.len == 0) return null;
561 return &self.items[self.items.len - 1];
562 }
555563 };
556564}
557565
......@@ -1391,15 +1399,16 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
13911399 return self.allocatedSlice()[self.items.len..];
13921400 }
13931401
1394 /// Deprecated in favor of `last`.
1395 pub fn getLast(self: Self) ?T {
1402 /// Returns the last element from the list, or `null` if the list is
1403 /// empty.
1404 pub fn last(self: Self) ?T {
13961405 if (self.items.len == 0) return null;
13971406 return self.items[self.items.len - 1];
13981407 }
13991408
14001409 /// Returns a pointer to the last element from the list, or `null` if
14011410 /// the list is empty.
1402 pub fn last(self: Self) ?*T {
1411 pub fn lastPtr(self: Self) ?*T {
14031412 if (self.items.len == 0) return null;
14041413 return &self.items[self.items.len - 1];
14051414 }
......@@ -2398,7 +2407,7 @@ test "last" {
23982407 try testing.expectEqual(list.last(), null);
23992408
24002409 try list.append(a, 2);
2401 try testing.expectEqual(list.last().?.*, 2);
2410 try testing.expectEqual(list.last().?, 2);
24022411}
24032412
24042413test "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.getLast(), q.back());
699 try testing.expectEqual(l.last(), 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
......@@ -3459,7 +3459,7 @@ const AutoIndentingStream = struct {
34593459 /// Sets current indentation level to be the same as that of the last pushSpace.
34603460 pub fn enableSpaceMode(ais: *AutoIndentingStream, space: Space) void {
34613461 if (ais.space_stack.items.len == 0) return;
3462 const curr = ais.space_stack.getLast().?;
3462 const curr = ais.space_stack.last().?;
34633463 if (curr.space != space) return;
34643464 ais.space_mode = curr.indent_count;
34653465 }
......@@ -3470,7 +3470,7 @@ const AutoIndentingStream = struct {
34703470
34713471 pub fn lastSpaceModeIndent(ais: *AutoIndentingStream) usize {
34723472 if (ais.space_stack.items.len == 0) return 0;
3473 return ais.space_stack.getLast().?.indent_count * ais.indent_delta;
3473 return ais.space_stack.last().?.indent_count * ais.indent_delta;
34743474 }
34753475
34763476 /// 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.last().?)) {
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.last().? == '\\') _ = 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.last().? == '\\') _ = 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.last().? == '\\') _ = path.pop();
11351135 break :base_path path;
11361136 }
11371137 return error.PathNotFound;
lib/std/zig/llvm/Builder.zig+4-4
......@@ -2962,7 +2962,7 @@ pub fn trailingStrtabString(self: *Builder) Allocator.Error!StrtabString {
29622962}
29632963
29642964pub fn trailingStrtabStringAssumeCapacity(self: *Builder) StrtabString {
2965 const start = self.strtab_string_indices.getLast().?;
2965 const start = self.strtab_string_indices.last().?;
29662966 const bytes: []const u8 = self.strtab_string_bytes.items[start..];
29672967 const gop = self.strtab_string_map.getOrPutAssumeCapacityAdapted(bytes, StrtabString.Adapter{ .builder = self });
29682968 if (gop.found_existing) {
......@@ -9765,7 +9765,7 @@ pub fn deinit(self: *Builder) void {
97659765
97669766pub fn finishModuleAsm(self: *Builder, aw: *Writer.Allocating) Allocator.Error!void {
97679767 self.module_asm = aw.toArrayList();
9768 if (self.module_asm.getLast()) |last| if (last != '\n')
9768 if (self.module_asm.last()) |last| if (last != '\n')
97699769 try self.module_asm.append(self.gpa, '\n');
97709770}
97719771
......@@ -9811,7 +9811,7 @@ pub fn trailingString(self: *Builder) Allocator.Error!String {
98119811}
98129812
98139813pub fn trailingStringAssumeCapacity(self: *Builder) String {
9814 const start = self.string_indices.getLast().?;
9814 const start = self.string_indices.last().?;
98159815 const bytes: []const u8 = self.string_bytes.items[start..];
98169816 const gop = self.string_map.getOrPutAssumeCapacityAdapted(bytes, String.Adapter{ .builder = self });
98179817 if (gop.found_existing) {
......@@ -13042,7 +13042,7 @@ pub fn trailingMetadataString(self: *Builder) Allocator.Error!Metadata.String {
1304213042}
1304313043
1304413044pub fn trailingMetadataStringAssumeCapacity(self: *Builder) Metadata.String {
13045 const start = self.metadata_string_indices.getLast().?;
13045 const start = self.metadata_string_indices.last().?;
1304613046 const bytes: []const u8 = self.metadata_string_bytes.items[start..];
1304713047 assert(bytes.len > 0);
1304813048 const gop = self.metadata_string_map.getOrPutAssumeCapacityAdapted(bytes, Metadata.String.Adapter{ .builder = self });
src/codegen/llvm.zig+1-1
......@@ -618,7 +618,7 @@ pub const Object = struct {
618618 b.module_asm.appendSliceAssumeCapacity(assembly);
619619 b.module_asm.appendAssumeCapacity('\n');
620620 }
621 if (b.module_asm.getLast()) |last| {
621 if (b.module_asm.last()) |last| {
622622 if (last != '\n') try b.module_asm.append(gpa, '\n');
623623 }
624624 }
src/codegen/spirv/CodeGen.zig+2-2
......@@ -7280,7 +7280,7 @@ fn structuredBreak(cg: *CodeGen, target_block: Id) !void {
72807280 if (cg.block_terminated) return;
72817281
72827282 const gpa = cg.gpa;
7283 const sblock = cg.block_stack.getLast().?;
7283 const sblock = cg.block_stack.last().?;
72847284 const merge_block = switch (sblock.*) {
72857285 .selection => |*merge| blk: {
72867286 const merge_label = cg.allocId();
......@@ -7447,7 +7447,7 @@ fn lowerBlock(cg: *CodeGen, inst: Air.Inst.Index, body: []const Air.Inst.Index)
74477447 .operand_2 = this_block,
74487448 });
74497449
7450 const sblock = cg.block_stack.getLast().?;
7450 const sblock = cg.block_stack.last().?;
74517451
74527452 if (ty.isNoReturn(zcu)) {
74537453 // If this block is noreturn, this instruction is the last of a block,
src/codegen/x86_64/CodeGen.zig+2-2
......@@ -2152,7 +2152,7 @@ fn gen(
21522152
21532153 const epilogue = if (self.epilogue_relocs.items.len > 0) epilogue: {
21542154 var last_inst: Mir.Inst.Index = @intCast(self.mir_instructions.len - 1);
2155 while (self.epilogue_relocs.getLast() == last_inst) {
2155 while (self.epilogue_relocs.last() == last_inst) {
21562156 self.epilogue_relocs.items.len -= 1;
21572157 self.mir_instructions.set(last_inst, .{
21582158 .tag = .pseudo,
......@@ -176978,7 +176978,7 @@ fn lowerBlock(self: *CodeGen, inst: Air.Inst.Index, body: []const Air.Inst.Index
176978176978 defer block_data.value.deinit(self.gpa);
176979176979 if (block_data.value.relocs.items.len > 0) {
176980176980 var last_inst: Mir.Inst.Index = @intCast(self.mir_instructions.len - 1);
176981 while (block_data.value.relocs.getLast() == last_inst) {
176981 while (block_data.value.relocs.last() == last_inst) {
176982176982 block_data.value.relocs.items.len -= 1;
176983176983 self.mir_instructions.set(last_inst, .{
176984176984 .tag = .pseudo,
tools/bsp.zig+1-1
......@@ -21,7 +21,7 @@ pub fn main(init: std.process.Init) !void {
2121 }
2222 if (maker_args.items.len < 1) try maker_args.append(arena, "zig");
2323 if (maker_args.items.len < 2) try maker_args.append(arena, "build");
24 if (!std.mem.eql(u8, maker_args.last().?.*, "--listen=-")) try maker_args.append(arena, "--listen=-");
24 if (!std.mem.eql(u8, maker_args.last().?, "--listen=-")) try maker_args.append(arena, "--listen=-");
2525
2626 log.debug("cmd: {f}", .{std.zig.SubprocessCommand{
2727 .argv = maker_args.items,