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.

indexPack

Writes out a version 2 index for the given packfile, as documented in pack-format.

git.indexPack
pub fn indexPack(
    allocator: Allocator,
    format: Oid.Format,
    pack: *Io.File.Reader,
    index_writer: *Io.File.Writer,
) !void

File

Code

pub fn indexPack(
    allocator: Allocator,
    format: Oid.Format,
    pack: *Io.File.Reader,
    index_writer: *Io.File.Writer,
) !void {
    try pack.seekTo(0);

    var index_entries: std.AutoHashMapUnmanaged(Oid, IndexEntry) = .empty;
    defer index_entries.deinit(allocator);
    var pending_deltas: std.ArrayList(IndexEntry) = .empty;
    defer pending_deltas.deinit(allocator);

    const pack_checksum = try indexPackFirstPass(allocator, format, pack, &index_entries, &pending_deltas);

    var cache: ObjectCache = .{};
    defer cache.deinit(allocator);
    var remaining_deltas = pending_deltas.items.len;
    while (remaining_deltas > 0) {
        var i: usize = remaining_deltas;
        while (i > 0) {
            i -= 1;
            const delta = pending_deltas.items[i];
            if (try indexPackHashDelta(allocator, format, pack, delta, index_entries, &cache)) |oid| {
                try index_entries.put(allocator, oid, delta);
                _ = pending_deltas.swapRemove(i);
            }
        }
        if (pending_deltas.items.len == remaining_deltas) return error.IncompletePack;
        remaining_deltas = pending_deltas.items.len;
    }

    var oids: std.ArrayList(Oid) = .empty;
    defer oids.deinit(allocator);
    try oids.ensureTotalCapacityPrecise(allocator, index_entries.count());
    var index_entries_iter = index_entries.iterator();
    while (index_entries_iter.next()) |entry| {
        oids.appendAssumeCapacity(entry.key_ptr.*);
    }
    mem.sortUnstable(Oid, oids.items, {}, struct {
        fn lessThan(_: void, o1: Oid, o2: Oid) bool {
            return mem.lessThan(u8, o1.slice(), o2.slice());
        }
    }.lessThan);

    var fan_out_table: [256]u32 = undefined;
    var count: u32 = 0;
    var fan_out_index: u8 = 0;
    for (oids.items) |oid| {
        const key = oid.slice()[0];
        if (key > fan_out_index) {
            @memset(fan_out_table[fan_out_index..key], count);
            fan_out_index = key;
        }
        count += 1;
    }
    @memset(fan_out_table[fan_out_index..], count);

    var index_hashed_writer = Io.Writer.hashed(&index_writer.interface, Oid.Hasher.init(format), &.{});
    const writer = &index_hashed_writer.writer;
    try writer.writeAll(IndexHeader.signature);
    try writer.writeInt(u32, IndexHeader.supported_version, .big);
    for (fan_out_table) |fan_out_entry| {
        try writer.writeInt(u32, fan_out_entry, .big);
    }

    for (oids.items) |oid| {
        try writer.writeAll(oid.slice());
    }

    for (oids.items) |oid| {
        try writer.writeInt(u32, index_entries.get(oid).?.crc32, .big);
    }

    var big_offsets: std.ArrayList(u64) = .empty;
    defer big_offsets.deinit(allocator);
    for (oids.items) |oid| {
        const offset = index_entries.get(oid).?.offset;
        if (offset <= std.math.maxInt(u31)) {
            try writer.writeInt(u32, @intCast(offset), .big);
        } else {
            const index = big_offsets.items.len;
            try big_offsets.append(allocator, offset);
            try writer.writeInt(u32, @as(u32, @intCast(index)) | (1 << 31), .big);
        }
    }
    for (big_offsets.items) |offset| {
        try writer.writeInt(u64, offset, .big);
    }

    try writer.writeAll(pack_checksum.slice());
    const index_checksum = index_hashed_writer.hasher.finalResult();
    try index_writer.interface.writeAll(index_checksum.slice());
    try index_writer.end();
}