From d02d0b879c143e1495fc360845d6feec1ac293ed Mon Sep 17 00:00:00 2001 From: Saurabh Mishra Date: Sat, 2 May 2026 02:26:15 +0200 Subject: [PATCH] `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 --- lib/compiler/build_runner.zig | 2 +- lib/compiler/translate-c/MacroTranslator.zig | 2 +- lib/docs/wasm/markdown/Parser.zig | 22 +++++------ lib/std/array_list.zig | 41 +++++--------------- lib/std/deque.zig | 2 +- lib/std/zig/Ast/Render.zig | 4 +- lib/std/zig/WindowsSdk.zig | 8 ++-- lib/std/zig/llvm/Builder.zig | 8 ++-- src/codegen/llvm.zig | 2 +- src/codegen/spirv/CodeGen.zig | 4 +- src/codegen/x86_64/CodeGen.zig | 4 +- 11 files changed, 39 insertions(+), 60 deletions(-) diff --git a/lib/compiler/build_runner.zig b/lib/compiler/build_runner.zig index 5cfa73d71fdf710f3c7e4a34b92209d106d5503d..6d8b5cca706e4c59a58a4197a5b7b11ab7a5e068 100644 --- a/lib/compiler/build_runner.zig +++ b/lib/compiler/build_runner.zig @@ -1397,7 +1397,7 @@ fn makeStep( defer run.max_rss_mutex.unlock(io); run.available_rss += s.max_rss; dispatch_set.ensureUnusedCapacity(gpa, run.memory_blocked_steps.items.len) catch @panic("OOM"); - while (run.memory_blocked_steps.getLastOrNull()) |candidate| { + while (run.memory_blocked_steps.getLast()) |candidate| { if (run.available_rss < candidate.max_rss) break; assert(run.memory_blocked_steps.pop() == candidate); dispatch_set.appendAssumeCapacity(candidate); diff --git a/lib/compiler/translate-c/MacroTranslator.zig b/lib/compiler/translate-c/MacroTranslator.zig index 72733830a2abd5eb021c1a4d83116d02e89799bd..ed4cb8a997a0d87b1bc25d63a1a0f86b6501a313 100644 --- a/lib/compiler/translate-c/MacroTranslator.zig +++ b/lib/compiler/translate-c/MacroTranslator.zig @@ -361,7 +361,7 @@ fn parseCNumLit(mt: *MacroTranslator) ParseError!ZigNode { return error.ParseError; }, }); - if (bytes.getLast() == '.') { + if (bytes.getLast().? == '.') { bytes.appendAssumeCapacity('0'); } else if (mem.findAny(u8, bytes.items, ".eEpP") == null) { bytes.appendSliceAssumeCapacity(".0"); diff --git a/lib/docs/wasm/markdown/Parser.zig b/lib/docs/wasm/markdown/Parser.zig index 238b2b536ecd0cd46aeb263f409983f8b8fd0689..cb1800ff1621a2ca3548d3b839af9bbf3ebfacf1 100644 --- a/lib/docs/wasm/markdown/Parser.zig +++ b/lib/docs/wasm/markdown/Parser.zig @@ -209,7 +209,7 @@ pub fn feedLine(p: *Parser, line: []const u8) Allocator.Error!void { } else p.pending_blocks.items.len; const in_code_block = p.pending_blocks.items.len > 0 and - p.pending_blocks.getLast().tag == .code_block; + p.pending_blocks.getLast().?.tag == .code_block; const code_block_end = in_code_block and first_unmatched + 1 == p.pending_blocks.items.len; // 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 { if (maybe_block_start == null and !isBlank(rest_line) and p.pending_blocks.items.len > 0 and - p.pending_blocks.getLast().tag == .paragraph) + p.pending_blocks.getLast().?.tag == .paragraph) { try p.addScratchStringLine(mem.trimStart(u8, rest_line, " \t")); return; @@ -236,7 +236,7 @@ pub fn feedLine(p: *Parser, line: []const u8) Allocator.Error!void { // paragraphs. if (maybe_block_start != null and p.pending_blocks.items.len > 0 and - p.pending_blocks.getLast().tag == .paragraph) + p.pending_blocks.getLast().?.tag == .paragraph) { try p.closeLastBlock(); } @@ -259,7 +259,7 @@ pub fn feedLine(p: *Parser, line: []const u8) Allocator.Error!void { // Do not append the end of a code block (```) as textual content. if (code_block_end) return; - const can_accept = if (p.pending_blocks.getLastOrNull()) |last_pending_block| + const can_accept = if (p.pending_blocks.getLast()) |last_pending_block| last_pending_block.canAccept() else .blocks; @@ -273,7 +273,7 @@ pub fn feedLine(p: *Parser, line: []const u8) Allocator.Error!void { // loose, since we might just be looking at a blank line after the // end of the last item in the list. The final determination will be // made when appending the next child of the list or list item. - const maybe_containing_list_index = if (p.pending_blocks.items.len > 0 and p.pending_blocks.getLast().tag == .list_item) + const maybe_containing_list_index = if (p.pending_blocks.items.len > 0 and p.pending_blocks.getLast().?.tag == .list_item) p.pending_blocks.items.len - 2 else null; @@ -368,7 +368,7 @@ const BlockStart = struct { }; fn appendBlockStart(p: *Parser, block_start: BlockStart) !void { - if (p.pending_blocks.getLastOrNull()) |last_pending_block| { + if (p.pending_blocks.getLast()) |last_pending_block| { // Close the last block if it is a list and the new block is not a list item // or not of the same marker type. const should_close_list = last_pending_block.tag == .list and @@ -383,7 +383,7 @@ fn appendBlockStart(p: *Parser, block_start: BlockStart) !void { } } - if (p.pending_blocks.getLastOrNull()) |last_pending_block| { + if (p.pending_blocks.getLast()) |last_pending_block| { // If the last block is a list or list item, check for tightness based // on the last line. const maybe_containing_list = switch (last_pending_block.tag) { @@ -401,7 +401,7 @@ fn appendBlockStart(p: *Parser, block_start: BlockStart) !void { // Start a new list if the new block is a list item and there is no // containing list yet. if (block_start.tag == .list_item and - (p.pending_blocks.items.len == 0 or p.pending_blocks.getLast().tag != .list)) + (p.pending_blocks.items.len == 0 or p.pending_blocks.getLast().?.tag != .list)) { try p.pending_blocks.append(p.allocator, .{ .tag = .list, @@ -417,7 +417,7 @@ fn appendBlockStart(p: *Parser, block_start: BlockStart) !void { if (block_start.tag == .table_row) { // Likewise, table rows start a table implicitly. - if (p.pending_blocks.items.len == 0 or p.pending_blocks.getLast().tag != .table) { + if (p.pending_blocks.items.len == 0 or p.pending_blocks.getLast().?.tag != .table) { try p.pending_blocks.append(p.allocator, .{ .tag = .table, .data = .{ .table = .{ @@ -429,7 +429,7 @@ fn appendBlockStart(p: *Parser, block_start: BlockStart) !void { }); } - const current_row = p.scratch_extra.items.len - p.pending_blocks.getLast().extra_start; + const current_row = p.scratch_extra.items.len - p.pending_blocks.getLast().?.extra_start; if (current_row <= 1) { var buffer: [max_table_columns]Node.TableCellAlignment = undefined; const table_row = &block_start.data.table_row; @@ -441,7 +441,7 @@ fn appendBlockStart(p: *Parser, block_start: BlockStart) !void { // We need to go back and mark the header row and its column // alignments. const datas = p.nodes.items(.data); - const header_data = datas[p.scratch_extra.getLast()]; + const header_data = datas[p.scratch_extra.getLast().?]; for (p.extraChildren(header_data.container.children), 0..) |header_cell, i| { const alignment = if (i < alignments.len) alignments[i] else .unset; const cell_data = &datas[@intFromEnum(header_cell)].table_cell; diff --git a/lib/std/array_list.zig b/lib/std/array_list.zig index c70646acb3d4492b433c4928d188b3affcaaa98a..71a52b669f7b1b7296eb1ea72ee84b4effa11d9a 100644 --- a/lib/std/array_list.zig +++ b/lib/std/array_list.zig @@ -544,16 +544,13 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type return self.allocatedSlice()[self.items.len..]; } - /// Returns the last element from the list. - /// Asserts that the list is not empty. - pub fn getLast(self: Self) T { - return self.items[self.items.len - 1]; - } + /// Deprecated in favor of `getLast` + pub const getLastOrNull = getLast; - /// Returns the last element from the list, or `null` if list is empty. - pub fn getLastOrNull(self: Self) ?T { + /// Returns the last element from the list, or `null` if the list is empty. + pub fn getLast(self: Self) ?T { if (self.items.len == 0) return null; - return self.getLast(); + return self.items[self.items.len - 1]; } }; } @@ -1394,17 +1391,10 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { return self.allocatedSlice()[self.items.len..]; } - /// Return the last element from the list. - /// Asserts that the list is not empty. - pub fn getLast(self: Self) T { - return self.items[self.items.len - 1]; - } - - /// Return the last element from the list, or - /// return `null` if list is empty. - pub fn getLastOrNull(self: Self) ?T { + /// Returns the last element from the list, or `null` if the list is empty. + pub fn getLast(self: Self) ?T { if (self.items.len == 0) return null; - return self.getLast(); + return self.items[self.items.len - 1]; } /// Called when memory growth is necessary. Returns a capacity larger than @@ -2394,22 +2384,11 @@ test "Managed(u32).getLast()" { var list = Managed(u32).init(a); defer list.deinit(); - try list.append(2); - const const_list = list; - try testing.expectEqual(const_list.getLast(), 2); -} - -test "Managed(u32).getLastOrNull()" { - const a = testing.allocator; - - var list = Managed(u32).init(a); - defer list.deinit(); - - try testing.expectEqual(list.getLastOrNull(), null); + try testing.expectEqual(list.getLast(), null); try list.append(2); const const_list = list; - try testing.expectEqual(const_list.getLastOrNull().?, 2); + try testing.expectEqual(const_list.getLast().?, 2); } test "return OutOfMemory when capacity would exceed maximum usize integer value" { diff --git a/lib/std/deque.zig b/lib/std/deque.zig index d15aa5e55690e0de4320f4ad991e149c1a0a2c50..c21e1b86567f9f84b9e7078fb751f178b193e5e9 100644 --- a/lib/std/deque.zig +++ b/lib/std/deque.zig @@ -696,7 +696,7 @@ fn fuzzAgainstArrayList(_: void, smith: *std.testing.Smith) anyerror!void { try q.ensureTotalCapacityPrecise(q_gpa, q.len + growth); }, } - try testing.expectEqual(l.getLastOrNull(), q.back()); + try testing.expectEqual(l.getLast(), q.back()); try testing.expectEqual( if (l.items.len > 0) l.items[0] else null, q.front(), diff --git a/lib/std/zig/Ast/Render.zig b/lib/std/zig/Ast/Render.zig index c02020d8f7f33f33cfda1d72ee77e142ea541fe4..6c8c0c9143d147b0f2483148f305c7b00c1cf304 100644 --- a/lib/std/zig/Ast/Render.zig +++ b/lib/std/zig/Ast/Render.zig @@ -3442,7 +3442,7 @@ const AutoIndentingStream = struct { /// Sets current indentation level to be the same as that of the last pushSpace. pub fn enableSpaceMode(ais: *AutoIndentingStream, space: Space) void { if (ais.space_stack.items.len == 0) return; - const curr = ais.space_stack.getLast(); + const curr = ais.space_stack.getLast().?; if (curr.space != space) return; ais.space_mode = curr.indent_count; } @@ -3453,7 +3453,7 @@ const AutoIndentingStream = struct { pub fn lastSpaceModeIndent(ais: *AutoIndentingStream) usize { if (ais.space_stack.items.len == 0) return 0; - return ais.space_stack.getLast().indent_count * ais.indent_delta; + return ais.space_stack.getLast().?.indent_count * ais.indent_delta; } /// Push default indentation diff --git a/lib/std/zig/WindowsSdk.zig b/lib/std/zig/WindowsSdk.zig index 043b91f8ec82b5885e804c2edd09ba3dfa84bd12..cddeecbe633eb049abbf014caf49ee38fcfe0ce6 100644 --- a/lib/std/zig/WindowsSdk.zig +++ b/lib/std/zig/WindowsSdk.zig @@ -891,7 +891,7 @@ const MsvcLibDir = struct { lib_dir_buf.appendSliceAssumeCapacity(installation_path); - if (!Dir.path.isSep(lib_dir_buf.getLast())) { + if (!Dir.path.isSep(lib_dir_buf.getLast().?)) { try lib_dir_buf.append('\\'); } const installation_path_with_trailing_sep_len = lib_dir_buf.items.len; @@ -1064,7 +1064,7 @@ const MsvcLibDir = struct { errdefer msvc_dir.deinit(); // String might contain trailing slash, so trim it here - if (msvc_dir.items.len > "C:\\".len and msvc_dir.getLast() == '\\') _ = msvc_dir.pop(); + if (msvc_dir.items.len > "C:\\".len and msvc_dir.getLast().? == '\\') _ = msvc_dir.pop(); // Remove `\include` at the end of path if (std.mem.endsWith(u8, msvc_dir.items, "\\include")) { @@ -1108,7 +1108,7 @@ const MsvcLibDir = struct { try list.appendSlice(VS140COMNTOOLS); // C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\Tools // String might contain trailing slash, so trim it here - if (list.items.len > "C:\\".len and list.getLast() == '\\') _ = list.pop(); + if (list.items.len > "C:\\".len and list.getLast().? == '\\') _ = list.pop(); list.shrinkRetainingCapacity(list.items.len - "\\Common7\\Tools".len); // C:\Program Files (x86)\Microsoft Visual Studio 14.0 break :base_path list; } @@ -1131,7 +1131,7 @@ const MsvcLibDir = struct { errdefer path.deinit(); // String might contain trailing slash, so trim it here - if (path.items.len > "C:\\".len and path.getLast() == '\\') _ = path.pop(); + if (path.items.len > "C:\\".len and path.getLast().? == '\\') _ = path.pop(); break :base_path path; } return error.PathNotFound; diff --git a/lib/std/zig/llvm/Builder.zig b/lib/std/zig/llvm/Builder.zig index d6d5ca741e99b070c7960c50450163562c653bf8..f6b59d5c82e936f102f9c9fb654b455f22f97c59 100644 --- a/lib/std/zig/llvm/Builder.zig +++ b/lib/std/zig/llvm/Builder.zig @@ -2310,7 +2310,7 @@ pub fn trailingStrtabString(self: *Builder) Allocator.Error!StrtabString { } pub fn trailingStrtabStringAssumeCapacity(self: *Builder) StrtabString { - const start = self.strtab_string_indices.getLast(); + const start = self.strtab_string_indices.getLast().?; const bytes: []const u8 = self.strtab_string_bytes.items[start..]; const gop = self.strtab_string_map.getOrPutAssumeCapacityAdapted(bytes, StrtabString.Adapter{ .builder = self }); if (gop.found_existing) { @@ -8905,7 +8905,7 @@ pub fn deinit(self: *Builder) void { pub fn finishModuleAsm(self: *Builder, aw: *Writer.Allocating) Allocator.Error!void { self.module_asm = aw.toArrayList(); - if (self.module_asm.getLastOrNull()) |last| if (last != '\n') + if (self.module_asm.getLast()) |last| if (last != '\n') try self.module_asm.append(self.gpa, '\n'); } @@ -8951,7 +8951,7 @@ pub fn trailingString(self: *Builder) Allocator.Error!String { } pub fn trailingStringAssumeCapacity(self: *Builder) String { - const start = self.string_indices.getLast(); + const start = self.string_indices.getLast().?; const bytes: []const u8 = self.string_bytes.items[start..]; const gop = self.string_map.getOrPutAssumeCapacityAdapted(bytes, String.Adapter{ .builder = self }); if (gop.found_existing) { @@ -12150,7 +12150,7 @@ pub fn trailingMetadataString(self: *Builder) Allocator.Error!Metadata.String { } pub fn trailingMetadataStringAssumeCapacity(self: *Builder) Metadata.String { - const start = self.metadata_string_indices.getLast(); + const start = self.metadata_string_indices.getLast().?; const bytes: []const u8 = self.metadata_string_bytes.items[start..]; assert(bytes.len > 0); const gop = self.metadata_string_map.getOrPutAssumeCapacityAdapted(bytes, Metadata.String.Adapter{ .builder = self }); diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 62b6a447b61b68bfb05db3def1607eecd7c177b5..847191ec1d67a51efc586ce87e209f6915e51f4b 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -747,7 +747,7 @@ pub const Object = struct { b.module_asm.appendSliceAssumeCapacity(assembly); b.module_asm.appendAssumeCapacity('\n'); } - if (b.module_asm.getLastOrNull()) |last| { + if (b.module_asm.getLast()) |last| { if (last != '\n') try b.module_asm.append(gpa, '\n'); } } diff --git a/src/codegen/spirv/CodeGen.zig b/src/codegen/spirv/CodeGen.zig index e8f74b24228ca3eb2d39705b96f0873e51d2f91e..daf02bd8dcce573664a86585cc12f4bf4dc61298 100644 --- a/src/codegen/spirv/CodeGen.zig +++ b/src/codegen/spirv/CodeGen.zig @@ -4829,7 +4829,7 @@ fn structuredBreak(cg: *CodeGen, target_block: Id) !void { assert(cg.control_flow == .structured); const gpa = cg.module.gpa; - const sblock = cg.control_flow.structured.block_stack.getLast(); + const sblock = cg.control_flow.structured.block_stack.getLast().?; const merge_block = switch (sblock.*) { .selection => |*merge| blk: { const merge_label = cg.module.allocId(); @@ -5044,7 +5044,7 @@ fn lowerBlock(cg: *CodeGen, inst: Air.Inst.Index, body: []const Air.Inst.Index) .operand_2 = this_block, }); - const sblock = cf.block_stack.getLast(); + const sblock = cf.block_stack.getLast().?; if (ty.isNoReturn(zcu)) { // If this block is noreturn, this instruction is the last of a block, diff --git a/src/codegen/x86_64/CodeGen.zig b/src/codegen/x86_64/CodeGen.zig index 42faf353c2bdb72f8d17897cca7dab5448acb9e4..4cd5ac2f9c13768d9d63a1d063f372336cf01450 100644 --- a/src/codegen/x86_64/CodeGen.zig +++ b/src/codegen/x86_64/CodeGen.zig @@ -2065,7 +2065,7 @@ fn gen( const epilogue = if (self.epilogue_relocs.items.len > 0) epilogue: { var last_inst: Mir.Inst.Index = @intCast(self.mir_instructions.len - 1); - while (self.epilogue_relocs.getLastOrNull() == last_inst) { + while (self.epilogue_relocs.getLast() == last_inst) { self.epilogue_relocs.items.len -= 1; self.mir_instructions.set(last_inst, .{ .tag = .pseudo, @@ -176545,7 +176545,7 @@ fn lowerBlock(self: *CodeGen, inst: Air.Inst.Index, body: []const Air.Inst.Index defer block_data.value.deinit(self.gpa); if (block_data.value.relocs.items.len > 0) { var last_inst: Mir.Inst.Index = @intCast(self.mir_instructions.len - 1); - while (block_data.value.relocs.getLastOrNull() == last_inst) { + while (block_data.value.relocs.getLast() == last_inst) { block_data.value.relocs.items.len -= 1; self.mir_instructions.set(last_inst, .{ .tag = .pseudo, -- 2.54.0