zig/tools/update_crc_catalog.zig
2025-11-28 04:13:45 -08:00

227 lines
7.9 KiB
Zig

const std = @import("std");
const fs = std.fs;
const mem = std.mem;
const ascii = std.ascii;
const catalog_txt = @embedFile("crc/catalog.txt");
pub fn main() anyerror!void {
var arena_state = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena_state.deinit();
const arena = arena_state.allocator();
const args = try std.process.argsAlloc(arena);
if (args.len <= 1) printUsageAndExit(args[0]);
const zig_src_root = args[1];
if (mem.startsWith(u8, zig_src_root, "-")) printUsageAndExit(args[0]);
var zig_src_dir = try fs.cwd().openDir(zig_src_root, .{});
defer zig_src_dir.close();
const hash_sub_path = try fs.path.join(arena, &.{ "lib", "std", "hash" });
var hash_target_dir = try zig_src_dir.makeOpenPath(hash_sub_path, .{});
defer hash_target_dir.close();
const crc_sub_path = try fs.path.join(arena, &.{ "lib", "std", "hash", "crc" });
var crc_target_dir = try zig_src_dir.makeOpenPath(crc_sub_path, .{});
defer crc_target_dir.close();
var zig_code_file = try hash_target_dir.createFile("crc.zig", .{});
defer zig_code_file.close();
var zig_code_file_buffer: [4096]u8 = undefined;
var zig_code_file_writer = zig_code_file.writer(&zig_code_file_buffer);
const code_writer = &zig_code_file_writer.interface;
try code_writer.writeAll(
\\//! This file is auto-generated by tools/update_crc_catalog.zig.
\\
\\const builtin = @import("builtin");
\\const impl = @import("crc/impl.zig");
\\
\\pub const Crc = impl.Crc;
\\pub const Polynomial = impl.Polynomial;
\\pub const Crc32WithPoly = impl.Crc32WithPoly;
\\pub const Crc32SmallWithPoly = impl.Crc32SmallWithPoly;
\\
\\pub const Crc32 = Crc32IsoHdlc;
\\
\\test {
\\ _ = @import("crc/test.zig");
\\}
\\
\\pub const Crc32Iscsi = switch (builtin.cpu.has(.x86, .crc32)) {
\\ true => @import("crc/crc32c.zig").Wrapper,
\\ else => Crc(u32, .{
\\ .polynomial = 0x1edc6f41,
\\ .initial = 0xffffffff,
\\ .reflect_input = true,
\\ .reflect_output = true,
\\ .xor_output = 0xffffffff,
\\ }),
\\};
\\
);
var zig_test_file = try crc_target_dir.createFile("test.zig", .{});
defer zig_test_file.close();
var zig_test_file_buffer: [4096]u8 = undefined;
var zig_test_file_writer = zig_test_file.writer(&zig_test_file_buffer);
const test_writer = &zig_test_file_writer.interface;
try test_writer.writeAll(
\\//! This file is auto-generated by tools/update_crc_catalog.zig.
\\
\\const std = @import("std");
\\const testing = std.testing;
\\const verify = @import("../verify.zig");
\\const crc = @import("../crc.zig");
\\
\\test "crc32 ieee regression" {
\\ const crc32 = crc.Crc32IsoHdlc;
\\ try testing.expectEqual(crc32.hash(""), 0x00000000);
\\ try testing.expectEqual(crc32.hash("a"), 0xe8b7be43);
\\ try testing.expectEqual(crc32.hash("abc"), 0x352441c2);
\\}
\\
\\test "crc32 castagnoli regression" {
\\ const crc32 = crc.Crc32Iscsi;
\\ try testing.expectEqual(crc32.hash(""), 0x00000000);
\\ try testing.expectEqual(crc32.hash("a"), 0xc1d04330);
\\ try testing.expectEqual(crc32.hash("abc"), 0x364b3fb7);
\\}
\\
\\test "crc32 koopman regression" {
\\ const crc32 = crc.Crc32Koopman;
\\ try testing.expectEqual(crc32.hash(""), 0x00000000);
\\ try testing.expectEqual(crc32.hash("a"), 0x0da2aa8a);
\\ try testing.expectEqual(crc32.hash("abc"), 0xba2322ac);
\\}
\\
\\test "CRC-32/ISCSI" {
\\ const Crc32Iscsi = crc.Crc32Iscsi;
\\
\\ try testing.expectEqual(@as(u32, 0xe3069283), Crc32Iscsi.hash("123456789"));
\\
\\ var c = Crc32Iscsi.init();
\\ c.update("1234");
\\ c.update("56789");
\\ try testing.expectEqual(@as(u32, 0xe3069283), c.final());
\\}
\\
);
var reader: std.Io.Reader = .fixed(catalog_txt);
while (try reader.takeDelimiter('\n')) |line| {
if (line.len == 0 or line[0] == '#')
continue;
var width: []const u8 = undefined;
var poly: []const u8 = undefined;
var init: []const u8 = undefined;
var refin: []const u8 = undefined;
var refout: []const u8 = undefined;
var xorout: []const u8 = undefined;
var check: []const u8 = undefined;
var residue: []const u8 = undefined;
var name: []const u8 = undefined;
var it = mem.splitSequence(u8, line, " ");
while (it.next()) |property| {
const i = mem.indexOf(u8, property, "=").?;
const key = property[0..i];
const value = property[i + 1 ..];
if (mem.eql(u8, key, "width")) {
width = value;
} else if (mem.eql(u8, key, "poly")) {
poly = value;
} else if (mem.eql(u8, key, "init")) {
init = value;
} else if (mem.eql(u8, key, "refin")) {
refin = value;
} else if (mem.eql(u8, key, "refout")) {
refout = value;
} else if (mem.eql(u8, key, "xorout")) {
xorout = value;
} else if (mem.eql(u8, key, "check")) {
check = value;
} else if (mem.eql(u8, key, "residue")) {
residue = value;
} else if (mem.eql(u8, key, "name")) {
name = mem.trim(u8, value, "\"");
} else {
unreachable;
}
}
const snakecase = try ascii.allocLowerString(arena, name);
defer arena.free(snakecase);
_ = mem.replace(u8, snakecase, "-", "_", snakecase);
_ = mem.replace(u8, snakecase, "/", "_", snakecase);
var buf = try std.array_list.Managed(u8).initCapacity(arena, snakecase.len);
defer buf.deinit();
var prev: u8 = 0;
for (snakecase, 0..) |c, i| {
if (c == '_') {
// do nothing
} else if (i == 0) {
buf.appendAssumeCapacity(ascii.toUpper(c));
} else if (prev == '_') {
buf.appendAssumeCapacity(ascii.toUpper(c));
} else {
buf.appendAssumeCapacity(c);
}
prev = c;
}
const camelcase = buf.items;
try code_writer.writeAll(try std.fmt.allocPrint(arena,
\\
\\pub const {s} = Crc(u{s}, .{{
\\ .polynomial = {s},
\\ .initial = {s},
\\ .reflect_input = {s},
\\ .reflect_output = {s},
\\ .xor_output = {s},
\\}});
\\
, .{ camelcase, width, poly, init, refin, refout, xorout }));
try test_writer.writeAll(try std.fmt.allocPrint(arena,
\\
\\test "{0s}" {{
\\ const {1s} = crc.{1s};
\\
\\ try testing.expectEqual(@as(u{2s}, {3s}), {1s}.hash("123456789"));
\\
\\ var c = {1s}.init();
\\ c.update("1234");
\\ c.update("56789");
\\ try testing.expectEqual(@as(u{2s}, {3s}), c.final());
\\}}
\\
, .{ name, camelcase, width, check }));
}
try code_writer.flush();
try test_writer.flush();
}
fn printUsageAndExit(arg0: []const u8) noreturn {
const w, _ = std.debug.lockStderrWriter(&.{});
defer std.debug.unlockStderrWriter();
printUsage(w, arg0) catch std.process.exit(2);
std.process.exit(1);
}
fn printUsage(w: *std.Io.Writer, arg0: []const u8) std.Io.Writer.Error!void {
return w.print(
\\Usage: {s} /path/git/zig
\\
, .{arg0});
}