authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-08-24 08:39:50+01:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-08-24 20:42:40+01:00
log7ece5e656da5cdd991f9fd1cb289f71c586a9210
tree1b45d684c0f3548f263cb020c7ce1594aceb3070
parent96c9ff1c93532e7c2764449e0cd6f39d4dce2285
signaturelock-open Commit is signed but in an unrecognized format.

link.MappedFile: remove unnecessary child iterator

There are now functions for `first`, `last`, `prev`, and `next`, so there is no need for a separate abstraction wrapping a simple linked list iteration.

3 files changed, 56 insertions(+), 64 deletions(-)

src/link/Coff.zig+40-35
...@@ -3546,16 +3546,20 @@ fn objectSectionMapIndex(...@@ -3546,16 +3546,20 @@ fn objectSectionMapIndex(
3546 try coff.symbols.ensureUnusedCapacity(gpa, 1);3546 try coff.symbols.ensureUnusedCapacity(gpa, 1);
3547 const parent_ni = parent.node(coff);3547 const parent_ni = parent.node(coff);
3548 var prev_oni: MappedFile.Node.Index.Optional = .none;3548 var prev_oni: MappedFile.Node.Index.Optional = .none;
3549 var next_it = parent_ni.children(&coff.mf);3549 {
3550 while (next_it.next()) |next_ni| switch (std.mem.order(3550 var child_oni = parent_ni.first(&coff.mf);
3551 u8,3551 while (child_oni.unwrap()) |child_ni| : (child_oni = child_ni.next(&coff.mf)) {
3552 name_slice,3552 switch (std.mem.order(
3553 coff.getNode(next_ni).object_section.name(coff).toSlice(coff),3553 u8,
3554 )) {3554 name_slice,
3555 .lt => break,3555 coff.getNode(child_ni).object_section.name(coff).toSlice(coff),
3556 .eq => unreachable,3556 )) {
3557 .gt => prev_oni = .wrap(next_ni),3557 .lt => break,
3558 };3558 .eq => unreachable,
3559 .gt => prev_oni = .wrap(child_ni),
3560 }
3561 }
3562 }
3559 const ni = try parent_ni.addHeaderChildAfter(&coff.mf, gpa, prev_oni, .{3563 const ni = try parent_ni.addHeaderChildAfter(&coff.mf, gpa, prev_oni, .{
3560 .alignment = alignment,3564 .alignment = alignment,
3561 });3565 });
...@@ -7025,7 +7029,7 @@ fn flushResized(coff: *Coff, ni: MappedFile.Node.Index) !void {...@@ -7025,7 +7029,7 @@ fn flushResized(coff: *Coff, ni: MappedFile.Node.Index) !void {
7025 if (coff.isArchive() and coff.members.items.len > 0) {7029 if (coff.isArchive() and coff.members.items.len > 0) {
7026 const last_member = coff.members.items[coff.members.items.len - 1];7030 const last_member = coff.members.items[coff.members.items.len - 1];
7027 // See .archive_member branch for reasoning7031 // See .archive_member branch for reasoning
7028 assert(Node.known.file.reverseChildren(&coff.mf).ni == last_member.content_ni.toOptional());7032 assert(Node.known.file.last(&coff.mf).unwrap().? == last_member.content_ni);
7029 try coff.flushResized(last_member.content_ni);7033 try coff.flushResized(last_member.content_ni);
7030 }7034 }
7031 },7035 },
...@@ -7717,30 +7721,31 @@ pub fn printNode(...@@ -7717,30 +7721,31 @@ pub fn printNode(
7717 if (mf_node.flags.has_content) " has_content" else "",7721 if (mf_node.flags.has_content) " has_content" else "",
7718 });7722 });
7719 }7723 }
7720 var leaf = true;7724 if (ni.first(&coff.mf).unwrap()) |first_ni| {
7721 var child_it = ni.children(&coff.mf);7725 // non-leaf, just print children
7722 while (child_it.next()) |child_ni| {7726 var child_ni = first_ni;
7723 leaf = false;7727 while (true) {
7724 try coff.printNode(tid, w, child_ni, indent + 1);7728 try coff.printNode(tid, w, child_ni, indent + 1);
7725 }7729 child_ni = child_ni.next(&coff.mf).unwrap() orelse break;
7726 if (leaf) {
7727 const file_loc = ni.fileLocation(&coff.mf, false);
7728 if (file_loc.size == 0) return;
7729 var address = file_loc.offset;
7730 const line_len = 0x10;
7731 var line_it = std.mem.window(
7732 u8,
7733 coff.mf.memory_map.memory[@intCast(file_loc.offset)..][0..@intCast(file_loc.size)],
7734 line_len,
7735 line_len,
7736 );
7737 while (line_it.next()) |line_bytes| : (address += line_len) {
7738 try w.splatByteAll(' ', indent + 1);
7739 try w.print("{x:0>8} ", .{address});
7740 for (line_bytes) |byte| try w.print("{x:0>2} ", .{byte});
7741 try w.splatByteAll(' ', 3 * (line_len - line_bytes.len) + 1);
7742 for (line_bytes) |byte| try w.writeByte(if (std.ascii.isPrint(byte)) byte else '.');
7743 try w.writeByte('\n');
7744 }7730 }
7731 return;
7732 }
7733 const file_loc = ni.fileLocation(&coff.mf, false);
7734 if (file_loc.size == 0) return;
7735 var address = file_loc.offset;
7736 const line_len = 0x10;
7737 var line_it = std.mem.window(
7738 u8,
7739 coff.mf.memory_map.memory[@intCast(file_loc.offset)..][0..@intCast(file_loc.size)],
7740 line_len,
7741 line_len,
7742 );
7743 while (line_it.next()) |line_bytes| : (address += line_len) {
7744 try w.splatByteAll(' ', indent + 1);
7745 try w.print("{x:0>8} ", .{address});
7746 for (line_bytes) |byte| try w.print("{x:0>2} ", .{byte});
7747 try w.splatByteAll(' ', 3 * (line_len - line_bytes.len) + 1);
7748 for (line_bytes) |byte| try w.writeByte(if (std.ascii.isPrint(byte)) byte else '.');
7749 try w.writeByte('\n');
7745 }7750 }
7746}7751}
src/link/Elf2.zig+16-11
...@@ -7902,8 +7902,10 @@ fn flushElfOffset(elf: *Elf, ni: MappedFile.Node.Index) void {...@@ -7902,8 +7902,10 @@ fn flushElfOffset(elf: *Elf, ni: MappedFile.Node.Index) void {
7902 }7902 }
7903 },7903 },
7904 }7904 }
7905 var child_it = ni.children(&elf.mf);7905 var child_oni = ni.first(&elf.mf);
7906 while (child_it.next()) |child_ni| elf.flushElfOffset(child_ni);7906 while (child_oni.unwrap()) |child_ni| : (child_oni = child_ni.next(&elf.mf)) {
7907 elf.flushElfOffset(child_ni);
7908 }
7907 },7909 },
7908 .section => |shndx| switch (elf.shdrPtr(shndx)) {7910 .section => |shndx| switch (elf.shdrPtr(shndx)) {
7909 inline else => |shdr| elf.targetStore(&shdr.offset, @intCast(elf_offset)),7911 inline else => |shdr| elf.targetStore(&shdr.offset, @intCast(elf_offset)),
...@@ -8203,9 +8205,10 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!vo...@@ -8203,9 +8205,10 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!vo
8203 _, const size = ni.location(&elf.mf).resolve(&elf.mf);8205 _, const size = ni.location(&elf.mf).resolve(&elf.mf);
8204 switch (elf.getNode(ni)) {8206 switch (elf.getNode(ni)) {
8205 .archive => {8207 .archive => {
8206 var child_it = ni.reverseChildren(&elf.mf);8208 if (ni.last(&elf.mf).unwrap()) |last_ni| {
8207 if (child_it.next()) |last_ni| {8209 if (last_ni.prev(&elf.mf).unwrap()) |prev_ni| {
8208 if (child_it.next()) |prev_ni| if (prev_ni.hasNextMoved(&elf.mf)) return;8210 if (prev_ni.hasNextMoved(&elf.mf)) return;
8211 }
8209 const offset, _ = last_ni.location(&elf.mf).resolve(&elf.mf);8212 const offset, _ = last_ni.location(&elf.mf).resolve(&elf.mf);
8210 _ = std.mem.print(&elf.arHdrPtr(last_ni).ar_size, "{d:<10}", .{8213 _ = std.mem.print(&elf.arHdrPtr(last_ni).ar_size, "{d:<10}", .{
8211 size - offset,8214 size - offset,
...@@ -8894,13 +8897,15 @@ pub fn printNode(...@@ -8894,13 +8897,15 @@ pub fn printNode(
8894 if (mf_node.flags.has_content) " has_content" else "",8897 if (mf_node.flags.has_content) " has_content" else "",
8895 });8898 });
8896 }8899 }
8897 var leaf = true;8900 if (ni.first(&elf.mf).unwrap()) |first_ni| {
8898 var child_it = ni.children(&elf.mf);8901 // non-leaf, just print children
8899 while (child_it.next()) |child_ni| {8902 var child_ni = first_ni;
8900 leaf = false;8903 while (true) {
8901 try elf.printNode(tid, w, child_ni, indent + 1);8904 try elf.printNode(tid, w, child_ni, indent + 1);
8905 child_ni = child_ni.next(&elf.mf).unwrap() orelse break;
8906 }
8907 return;
8902 }8908 }
8903 if (!leaf) return;
8904 const file_loc = ni.fileLocation(&elf.mf, false);8909 const file_loc = ni.fileLocation(&elf.mf, false);
8905 var address = file_loc.offset;8910 var address = file_loc.offset;
8906 if (file_loc.size == 0) {8911 if (file_loc.size == 0) {
src/link/MappedFile.zig-18
...@@ -486,24 +486,6 @@ pub const Node = extern struct {...@@ -486,24 +486,6 @@ pub const Node = extern struct {
486 return ni.get(mf).prev;486 return ni.get(mf).prev;
487 }487 }
488488
489 pub fn ChildIterator(comptime direction: enum { prev, next }) type {
490 return struct {
491 mf: *const MappedFile,
492 ni: Node.Index.Optional,
493 pub fn next(it: *@This()) ?Node.Index {
494 const ni = it.ni.unwrap() orelse return null;
495 it.ni = @field(ni.get(it.mf), @tagName(direction));
496 return ni;
497 }
498 };
499 }
500 pub fn children(ni: Node.Index, mf: *const MappedFile) ChildIterator(.next) {
501 return .{ .mf = mf, .ni = ni.get(mf).first };
502 }
503 pub fn reverseChildren(ni: Node.Index, mf: *const MappedFile) ChildIterator(.prev) {
504 return .{ .mf = mf, .ni = ni.get(mf).last };
505 }
506
507 pub fn childrenMoved(ni: Node.Index, gpa: Allocator, mf: *MappedFile) Allocator.Error!void {489 pub fn childrenMoved(ni: Node.Index, gpa: Allocator, mf: *MappedFile) Allocator.Error!void {
508 var child_oni = ni.get(mf).last;490 var child_oni = ni.get(mf).last;
509 while (child_oni.unwrap()) |child_ni| {491 while (child_oni.unwrap()) |child_ni| {