mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 06:13:07 +00:00
This flips things around such that std/hash/crc.zig is generated by the catalog-based generation tool, and the real code that used to be in that file is moved out to std/hash/crc/impl.zig. The generated tests are moved to std/hash/crc/test.zig. By going this route, we eliminate the need for usingnamespace without changing anything for callers of these interfaces. The Crc32 tests are simply added to the fixed part of the generated output and compactified a bit. This was the second-to-last usage of usingnamespace left in std.
242 lines
7.7 KiB
Zig
242 lines
7.7 KiB
Zig
// There is a generic CRC implementation "Crc()" which can be paramterized via
|
|
// the Algorithm struct for a plethora of uses, along with two implementations
|
|
// of CRC32 implemented with the following key characteristics:
|
|
//
|
|
// - Crc32WithPoly uses 8Kb of tables but is ~10x faster than the small method.
|
|
//
|
|
// - Crc32SmallWithPoly uses only 64 bytes of memory but is slower. Be aware that this is
|
|
// still moderately fast just slow relative to the slicing approach.
|
|
//
|
|
// The primary interface for all of the standard CRC algorithms is the
|
|
// generated file "crc.zig", which uses the implementation code here to define
|
|
// many standard CRCs.
|
|
|
|
const std = @import("std");
|
|
|
|
pub fn Algorithm(comptime W: type) type {
|
|
return struct {
|
|
polynomial: W,
|
|
initial: W,
|
|
reflect_input: bool,
|
|
reflect_output: bool,
|
|
xor_output: W,
|
|
};
|
|
}
|
|
|
|
pub fn Crc(comptime W: type, comptime algorithm: Algorithm(W)) type {
|
|
return struct {
|
|
const Self = @This();
|
|
const I = if (@bitSizeOf(W) < 8) u8 else W;
|
|
const lookup_table = blk: {
|
|
@setEvalBranchQuota(2500);
|
|
|
|
const poly = if (algorithm.reflect_input)
|
|
@bitReverse(@as(I, algorithm.polynomial)) >> (@bitSizeOf(I) - @bitSizeOf(W))
|
|
else
|
|
@as(I, algorithm.polynomial) << (@bitSizeOf(I) - @bitSizeOf(W));
|
|
|
|
var table: [256]I = undefined;
|
|
for (&table, 0..) |*e, i| {
|
|
var crc: I = i;
|
|
if (algorithm.reflect_input) {
|
|
var j: usize = 0;
|
|
while (j < 8) : (j += 1) {
|
|
crc = (crc >> 1) ^ ((crc & 1) * poly);
|
|
}
|
|
} else {
|
|
crc <<= @bitSizeOf(I) - 8;
|
|
var j: usize = 0;
|
|
while (j < 8) : (j += 1) {
|
|
crc = (crc << 1) ^ (((crc >> (@bitSizeOf(I) - 1)) & 1) * poly);
|
|
}
|
|
}
|
|
e.* = crc;
|
|
}
|
|
break :blk table;
|
|
};
|
|
|
|
crc: I,
|
|
|
|
pub fn init() Self {
|
|
const initial = if (algorithm.reflect_input)
|
|
@bitReverse(@as(I, algorithm.initial)) >> (@bitSizeOf(I) - @bitSizeOf(W))
|
|
else
|
|
@as(I, algorithm.initial) << (@bitSizeOf(I) - @bitSizeOf(W));
|
|
return Self{ .crc = initial };
|
|
}
|
|
|
|
inline fn tableEntry(index: I) I {
|
|
return lookup_table[@as(u8, @intCast(index & 0xFF))];
|
|
}
|
|
|
|
pub fn update(self: *Self, bytes: []const u8) void {
|
|
var i: usize = 0;
|
|
if (@bitSizeOf(I) <= 8) {
|
|
while (i < bytes.len) : (i += 1) {
|
|
self.crc = tableEntry(self.crc ^ bytes[i]);
|
|
}
|
|
} else if (algorithm.reflect_input) {
|
|
while (i < bytes.len) : (i += 1) {
|
|
const table_index = self.crc ^ bytes[i];
|
|
self.crc = tableEntry(table_index) ^ (self.crc >> 8);
|
|
}
|
|
} else {
|
|
while (i < bytes.len) : (i += 1) {
|
|
const table_index = (self.crc >> (@bitSizeOf(I) - 8)) ^ bytes[i];
|
|
self.crc = tableEntry(table_index) ^ (self.crc << 8);
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn final(self: Self) W {
|
|
var c = self.crc;
|
|
if (algorithm.reflect_input != algorithm.reflect_output) {
|
|
c = @bitReverse(c);
|
|
}
|
|
if (!algorithm.reflect_output) {
|
|
c >>= @bitSizeOf(I) - @bitSizeOf(W);
|
|
}
|
|
return @as(W, @intCast(c ^ algorithm.xor_output));
|
|
}
|
|
|
|
pub fn hash(bytes: []const u8) W {
|
|
var c = Self.init();
|
|
c.update(bytes);
|
|
return c.final();
|
|
}
|
|
};
|
|
}
|
|
|
|
pub const Polynomial = enum(u32) {
|
|
IEEE = 0xedb88320,
|
|
Castagnoli = 0x82f63b78,
|
|
Koopman = 0xeb31d82e,
|
|
_,
|
|
};
|
|
|
|
// slicing-by-8 crc32 implementation.
|
|
pub fn Crc32WithPoly(comptime poly: Polynomial) type {
|
|
return struct {
|
|
const Self = @This();
|
|
const lookup_tables = block: {
|
|
@setEvalBranchQuota(20000);
|
|
var tables: [8][256]u32 = undefined;
|
|
|
|
for (&tables[0], 0..) |*e, i| {
|
|
var crc = @as(u32, @intCast(i));
|
|
var j: usize = 0;
|
|
while (j < 8) : (j += 1) {
|
|
if (crc & 1 == 1) {
|
|
crc = (crc >> 1) ^ @intFromEnum(poly);
|
|
} else {
|
|
crc = (crc >> 1);
|
|
}
|
|
}
|
|
e.* = crc;
|
|
}
|
|
|
|
var i: usize = 0;
|
|
while (i < 256) : (i += 1) {
|
|
var crc = tables[0][i];
|
|
var j: usize = 1;
|
|
while (j < 8) : (j += 1) {
|
|
const index: u8 = @truncate(crc);
|
|
crc = tables[0][index] ^ (crc >> 8);
|
|
tables[j][i] = crc;
|
|
}
|
|
}
|
|
|
|
break :block tables;
|
|
};
|
|
|
|
crc: u32,
|
|
|
|
pub fn init() Self {
|
|
return Self{ .crc = 0xffffffff };
|
|
}
|
|
|
|
pub fn update(self: *Self, input: []const u8) void {
|
|
var i: usize = 0;
|
|
while (i + 8 <= input.len) : (i += 8) {
|
|
const p = input[i..][0..8];
|
|
|
|
// Unrolling this way gives ~50Mb/s increase
|
|
self.crc ^= std.mem.readInt(u32, p[0..4], .little);
|
|
|
|
self.crc =
|
|
lookup_tables[0][p[7]] ^
|
|
lookup_tables[1][p[6]] ^
|
|
lookup_tables[2][p[5]] ^
|
|
lookup_tables[3][p[4]] ^
|
|
lookup_tables[4][@as(u8, @truncate(self.crc >> 24))] ^
|
|
lookup_tables[5][@as(u8, @truncate(self.crc >> 16))] ^
|
|
lookup_tables[6][@as(u8, @truncate(self.crc >> 8))] ^
|
|
lookup_tables[7][@as(u8, @truncate(self.crc >> 0))];
|
|
}
|
|
|
|
while (i < input.len) : (i += 1) {
|
|
const index = @as(u8, @truncate(self.crc)) ^ input[i];
|
|
self.crc = (self.crc >> 8) ^ lookup_tables[0][index];
|
|
}
|
|
}
|
|
|
|
pub fn final(self: *Self) u32 {
|
|
return ~self.crc;
|
|
}
|
|
|
|
pub fn hash(input: []const u8) u32 {
|
|
var c = Self.init();
|
|
c.update(input);
|
|
return c.final();
|
|
}
|
|
};
|
|
}
|
|
|
|
// half-byte lookup table implementation.
|
|
pub fn Crc32SmallWithPoly(comptime poly: Polynomial) type {
|
|
return struct {
|
|
const Self = @This();
|
|
const lookup_table = block: {
|
|
var table: [16]u32 = undefined;
|
|
|
|
for (&table, 0..) |*e, i| {
|
|
var crc = @as(u32, @intCast(i * 16));
|
|
var j: usize = 0;
|
|
while (j < 8) : (j += 1) {
|
|
if (crc & 1 == 1) {
|
|
crc = (crc >> 1) ^ @intFromEnum(poly);
|
|
} else {
|
|
crc = (crc >> 1);
|
|
}
|
|
}
|
|
e.* = crc;
|
|
}
|
|
|
|
break :block table;
|
|
};
|
|
|
|
crc: u32,
|
|
|
|
pub fn init() Self {
|
|
return Self{ .crc = 0xffffffff };
|
|
}
|
|
|
|
pub fn update(self: *Self, input: []const u8) void {
|
|
for (input) |b| {
|
|
self.crc = lookup_table[@as(u4, @truncate(self.crc ^ (b >> 0)))] ^ (self.crc >> 4);
|
|
self.crc = lookup_table[@as(u4, @truncate(self.crc ^ (b >> 4)))] ^ (self.crc >> 4);
|
|
}
|
|
}
|
|
|
|
pub fn final(self: *Self) u32 {
|
|
return ~self.crc;
|
|
}
|
|
|
|
pub fn hash(input: []const u8) u32 {
|
|
var c = Self.init();
|
|
c.update(input);
|
|
return c.final();
|
|
}
|
|
};
|
|
}
|