Zig 0.17.0-dev (Split by item)

This is an example of documentation generated by ZigDoc, an alternative to Zig's built-in Auto Doc feature. See also examples in other modes/formats. The project being documented here (as the example) is the Zig library itself.

iterateAndFilterByVersion

Iterates via iterator and collects all folders with names starting with strip_prefix and a version. Returns slice of version strings sorted in descending order. Caller owns result.

WindowsSdk.iterateAndFilterByVersion
fn iterateAndFilterByVersion(
    iterator: *Dir.Iterator,
    gpa: Allocator,
    io: Io,
    prefix: []const u8,
) error

File

lib/std/zig/WindowsSdk.zig:90

Code

fn iterateAndFilterByVersion(
    iterator: *Dir.Iterator,
    gpa: Allocator,
    io: Io,
    prefix: []const u8,
) error{OutOfMemory}![][]const u8 {
    const Version = struct {
        nums: [4]u32,
        build: []const u8,

        fn parseNum(num: []const u8) ?u32 {
            if (num[0] == '0' and num.len > 1) return null;
            return std.fmt.parseInt(u32, num, 10) catch null;
        }

        fn order(lhs: @This(), rhs: @This()) std.math.Order {
            return std.mem.order(u32, &lhs.nums, &rhs.nums).differ() orelse
                std.mem.order(u8, lhs.build, rhs.build);
        }
    };
    var versions = std.array_list.Managed(Version).init(gpa);
    var dirs = std.array_list.Managed([]const u8).init(gpa);
    defer {
        versions.deinit();
        for (dirs.items) |filtered_dir| gpa.free(filtered_dir);
        dirs.deinit();
    }

    iterate: while (iterator.next(io) catch null) |entry| {
        if (entry.kind != .directory) continue;
        if (!std.mem.startsWith(u8, entry.name, prefix)) continue;

        var version: Version = .{
            .nums = @splat(0),
            .build = "",
        };
        const suffix = entry.name[prefix.len..];
        const underscore = std.mem.findScalar(u8, entry.name, '_');
        var num_it = std.mem.splitScalar(u8, suffix[0 .. underscore orelse suffix.len], '.');
        version.nums[0] = Version.parseNum(num_it.first()) orelse continue;
        for (version.nums[1..]) |*num|
            num.* = Version.parseNum(num_it.next() orelse break) orelse continue :iterate
        else if (num_it.next()) |_| continue;

        const name = try gpa.dupe(u8, suffix);
        errdefer gpa.free(name);
        if (underscore) |pos| version.build = name[pos + 1 ..];

        try versions.append(version);
        try dirs.append(name);
    }

    std.mem.sortUnstableContext(0, dirs.items.len, struct {
        versions: []Version,
        dirs: [][]const u8,
        pub fn lessThan(context: @This(), lhs: usize, rhs: usize) bool {
            return context.versions[lhs].order(context.versions[rhs]).compare(.gt);
        }
        pub fn swap(context: @This(), lhs: usize, rhs: usize) void {
            std.mem.swap(Version, &context.versions[lhs], &context.versions[rhs]);
            std.mem.swap([]const u8, &context.dirs[lhs], &context.dirs[rhs]);
        }
    }{ .versions = versions.items, .dirs = dirs.items });
    return dirs.toOwnedSlice();
}