mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 14:23:09 +00:00
std.hash.crc: implement algorithms listed in CRC RevEng catalog
This commit is contained in:
parent
38eebf3c4d
commit
be4468be37
@ -10,6 +10,104 @@ const builtin = @import("builtin");
|
|||||||
const debug = std.debug;
|
const debug = std.debug;
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
|
|
||||||
|
pub usingnamespace @import("crc/catalog.zig");
|
||||||
|
|
||||||
|
pub fn Algorithm(comptime W: type) type {
|
||||||
|
return struct {
|
||||||
|
poly: W,
|
||||||
|
init: W,
|
||||||
|
refin: bool,
|
||||||
|
refout: bool,
|
||||||
|
xorout: W,
|
||||||
|
check: W,
|
||||||
|
residue: 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.refin)
|
||||||
|
@bitReverse(@as(I, algorithm.poly)) >> (@bitSizeOf(I) - @bitSizeOf(W))
|
||||||
|
else
|
||||||
|
@as(I, algorithm.poly) << (@bitSizeOf(I) - @bitSizeOf(W));
|
||||||
|
|
||||||
|
var table: [256]I = undefined;
|
||||||
|
for (table) |*e, i| {
|
||||||
|
var crc: I = i;
|
||||||
|
if (algorithm.refin) {
|
||||||
|
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.refin)
|
||||||
|
@bitReverse(@as(I, algorithm.init)) >> (@bitSizeOf(I) - @bitSizeOf(W))
|
||||||
|
else
|
||||||
|
@as(I, algorithm.init) << (@bitSizeOf(I) - @bitSizeOf(W));
|
||||||
|
return Self{ .crc = initial };
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fn tableEntry(index: I) I {
|
||||||
|
return lookup_table[@intCast(u8, 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.refin) {
|
||||||
|
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.refin != algorithm.refout) {
|
||||||
|
c = @bitReverse(c);
|
||||||
|
}
|
||||||
|
if (!algorithm.refout) {
|
||||||
|
c >>= @bitSizeOf(I) - @bitSizeOf(W);
|
||||||
|
}
|
||||||
|
return @intCast(W, c ^ algorithm.xorout);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn hash(bytes: []const u8) W {
|
||||||
|
var c = Self.init();
|
||||||
|
c.update(bytes);
|
||||||
|
return c.final();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
pub const Polynomial = enum(u32) {
|
pub const Polynomial = enum(u32) {
|
||||||
IEEE = 0xedb88320,
|
IEEE = 0xedb88320,
|
||||||
Castagnoli = 0x82f63b78,
|
Castagnoli = 0x82f63b78,
|
||||||
|
|||||||
1463
lib/std/hash/crc/catalog.zig
Normal file
1463
lib/std/hash/crc/catalog.zig
Normal file
File diff suppressed because it is too large
Load Diff
40
tools/update_crc_catalog.sh
Executable file
40
tools/update_crc_catalog.sh
Executable file
@ -0,0 +1,40 @@
|
|||||||
|
if [ $# -lt 1 ]; then
|
||||||
|
echo "Usage: $0 /path/git/zig"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
filepath=$1/lib/std/hash/crc/catalog.zig
|
||||||
|
|
||||||
|
cat <<EOS >$filepath
|
||||||
|
//! This file is auto-generated by tools/update_crc_catalog.sh.
|
||||||
|
|
||||||
|
const std = @import("../../std.zig");
|
||||||
|
const testing = std.testing;
|
||||||
|
const crc = @import("../crc.zig");
|
||||||
|
const Algorithm = crc.Algorithm;
|
||||||
|
const Crc = crc.Crc;
|
||||||
|
EOS
|
||||||
|
|
||||||
|
curl -s https://reveng.sourceforge.io/crc-catalogue/all.htm | grep -o 'width.*name.*"' | while read -r line; do
|
||||||
|
width=$(echo $line | sed 's/width=\([0-9]*\) \(.*\) name="\(.*\)"/\1/')
|
||||||
|
params=$(echo $line | sed 's/width=\([0-9]*\) \(.*\) name="\(.*\)"/\2/' | sed 's/ /, ./g' | sed 's/=/ = /g')
|
||||||
|
name=$(echo $line | sed 's/width=\([0-9]*\) \(.*\) name="\(.*\)"/\3/')
|
||||||
|
snakecase=$(echo $name | sed 's/[-\/]/_/g' | tr '[:upper:]' '[:lower:]')
|
||||||
|
camelcase=$(echo $snakecase | perl -pe 's/(^|_)(\w)/\U$2/g')
|
||||||
|
|
||||||
|
cat <<EOS >>$filepath
|
||||||
|
|
||||||
|
const $snakecase: Algorithm(u$width) = .{ .$params };
|
||||||
|
|
||||||
|
pub const $camelcase = Crc(u$width, $snakecase);
|
||||||
|
|
||||||
|
test "$name" {
|
||||||
|
try testing.expectEqual($snakecase.check, $camelcase.hash("123456789"));
|
||||||
|
|
||||||
|
var c = $camelcase.init();
|
||||||
|
c.update("1234");
|
||||||
|
c.update("56789");
|
||||||
|
try testing.expectEqual($snakecase.check, c.final());
|
||||||
|
}
|
||||||
|
EOS
|
||||||
|
done
|
||||||
Loading…
x
Reference in New Issue
Block a user