| author | |
| committer | |
| log | fc45e5b39c0e09dcf69cc65a92375bef0c9593cb |
| tree | 3b95615e2ef511c59e7dfc617edb77f176b72e9c |
| parent | 497f37ce92ba13aa609acce23135fd6b06ed410f |
| parent | 5f0ecafa0dddd9b630220d1c6cf4be2e42987faf |
| signature |
std.hash.crc: simplify api7 files changed, 65 insertions(+), 174 deletions(-)
lib/std/debug.zig+1-1| ... | @@ -1150,7 +1150,7 @@ pub fn readElfDebugInfo( | ... | @@ -1150,7 +1150,7 @@ pub fn readElfDebugInfo( |
| 1150 | }; | 1150 | }; |
| 1151 | 1151 | ||
| 1152 | const mapped_mem = try mapWholeFile(elf_file); | 1152 | const mapped_mem = try mapWholeFile(elf_file); |
| 1153 | if (expected_crc) |crc| if (crc != std.hash.crc.Crc32SmallWithPoly(.IEEE).hash(mapped_mem)) return error.InvalidDebugInfo; | 1153 | if (expected_crc) |crc| if (crc != std.hash.crc.Crc32.hash(mapped_mem)) return error.InvalidDebugInfo; |
| 1154 | 1154 | ||
| 1155 | const hdr: *const elf.Ehdr = @ptrCast(&mapped_mem[0]); | 1155 | const hdr: *const elf.Ehdr = @ptrCast(&mapped_mem[0]); |
| 1156 | if (!mem.eql(u8, hdr.e_ident[0..4], elf.MAGIC)) return error.InvalidElfMagic; | 1156 | if (!mem.eql(u8, hdr.e_ident[0..4], elf.MAGIC)) return error.InvalidElfMagic; |
lib/std/hash/benchmark.zig+2-6| ... | @@ -56,12 +56,8 @@ const hashes = [_]Hash{ | ... | @@ -56,12 +56,8 @@ const hashes = [_]Hash{ |
| 56 | .name = "adler32", | 56 | .name = "adler32", |
| 57 | }, | 57 | }, |
| 58 | Hash{ | 58 | Hash{ |
| 59 | .ty = hash.crc.Crc32WithPoly(.IEEE), | 59 | .ty = hash.crc.Crc32, |
| 60 | .name = "crc32-slicing-by-8", | 60 | .name = "crc32", |
| 61 | }, | ||
| 62 | Hash{ | ||
| 63 | .ty = hash.crc.Crc32SmallWithPoly(.IEEE), | ||
| 64 | .name = "crc32-half-byte-lookup", | ||
| 65 | }, | 61 | }, |
| 66 | Hash{ | 62 | Hash{ |
| 67 | .ty = hash.CityHash32, | 63 | .ty = hash.CityHash32, |
lib/std/hash/crc.zig+9-2| ... | @@ -7,8 +7,7 @@ pub const Polynomial = impl.Polynomial; | ... | @@ -7,8 +7,7 @@ pub const Polynomial = impl.Polynomial; |
| 7 | pub const Crc32WithPoly = impl.Crc32WithPoly; | 7 | pub const Crc32WithPoly = impl.Crc32WithPoly; |
| 8 | pub const Crc32SmallWithPoly = impl.Crc32SmallWithPoly; | 8 | pub const Crc32SmallWithPoly = impl.Crc32SmallWithPoly; |
| 9 | 9 | ||
| 10 | // IEEE is by far the most common CRC and so is aliased by default. | 10 | pub const Crc32 = Crc32IsoHdlc; |
| 11 | pub const Crc32 = Crc32WithPoly(.IEEE); | ||
| 12 | 11 | ||
| 13 | test { | 12 | test { |
| 14 | _ = @import("crc/test.zig"); | 13 | _ = @import("crc/test.zig"); |
| ... | @@ -822,6 +821,14 @@ pub const Crc32Jamcrc = Crc(u32, .{ | ... | @@ -822,6 +821,14 @@ pub const Crc32Jamcrc = Crc(u32, .{ |
| 822 | .xor_output = 0x00000000, | 821 | .xor_output = 0x00000000, |
| 823 | }); | 822 | }); |
| 824 | 823 | ||
| 824 | pub const Crc32Koopman = Crc(u32, .{ | ||
| 825 | .polynomial = 0x741b8cd7, | ||
| 826 | .initial = 0xffffffff, | ||
| 827 | .reflect_input = true, | ||
| 828 | .reflect_output = true, | ||
| 829 | .xor_output = 0xffffffff, | ||
| 830 | }); | ||
| 831 | |||
| 825 | pub const Crc32Mef = Crc(u32, .{ | 832 | pub const Crc32Mef = Crc(u32, .{ |
| 826 | .polynomial = 0x741b8cd7, | 833 | .polynomial = 0x741b8cd7, |
| 827 | .initial = 0xffffffff, | 834 | .initial = 0xffffffff, |
lib/std/hash/crc/impl.zig+6-135| ... | @@ -1,11 +1,5 @@ | ... | @@ -1,11 +1,5 @@ |
| 1 | // There is a generic CRC implementation "Crc()" which can be paramterized via | 1 | // There is a generic CRC implementation "Crc()" which can be paramterized via |
| 2 | // the Algorithm struct for a plethora of uses, along with two implementations | 2 | // the Algorithm struct for a plethora of uses. |
| 3 | // of CRC32 implemented with the following key characteristics: | ||
| 4 | // | ||
| 5 | // - Crc32WithPoly uses 8Kb of tables but is ~10x faster than the small method. | ||
| 6 | // | ||
| 7 | // - Crc32SmallWithPoly uses only 64 bytes of memory but is slower. Be aware that this is | ||
| 8 | // still moderately fast just slow relative to the slicing approach. | ||
| 9 | // | 3 | // |
| 10 | // The primary interface for all of the standard CRC algorithms is the | 4 | // The primary interface for all of the standard CRC algorithms is the |
| 11 | // generated file "crc.zig", which uses the implementation code here to define | 5 | // generated file "crc.zig", which uses the implementation code here to define |
| ... | @@ -108,134 +102,11 @@ pub fn Crc(comptime W: type, comptime algorithm: Algorithm(W)) type { | ... | @@ -108,134 +102,11 @@ pub fn Crc(comptime W: type, comptime algorithm: Algorithm(W)) type { |
| 108 | } | 102 | } |
| 109 | 103 | ||
| 110 | pub const Polynomial = enum(u32) { | 104 | pub const Polynomial = enum(u32) { |
| 111 | IEEE = 0xedb88320, | 105 | IEEE = @compileError("use Crc with algorithm .Crc32IsoHdlc"), |
| 112 | Castagnoli = 0x82f63b78, | 106 | Castagnoli = @compileError("use Crc with algorithm .Crc32Iscsi"), |
| 113 | Koopman = 0xeb31d82e, | 107 | Koopman = @compileError("use Crc with algorithm .Crc32Koopman"), |
| 114 | _, | 108 | _, |
| 115 | }; | 109 | }; |
| 116 | 110 | ||
| 117 | // slicing-by-8 crc32 implementation. | 111 | pub const Crc32WithPoly = @compileError("use Crc instead"); |
| 118 | pub fn Crc32WithPoly(comptime poly: Polynomial) type { | 112 | pub const Crc32SmallWithPoly = @compileError("use Crc instead"); |
| 119 | return struct { | ||
| 120 | const Self = @This(); | ||
| 121 | const lookup_tables = block: { | ||
| 122 | @setEvalBranchQuota(20000); | ||
| 123 | var tables: [8][256]u32 = undefined; | ||
| 124 | |||
| 125 | for (&tables[0], 0..) |*e, i| { | ||
| 126 | var crc = @as(u32, @intCast(i)); | ||
| 127 | var j: usize = 0; | ||
| 128 | while (j < 8) : (j += 1) { | ||
| 129 | if (crc & 1 == 1) { | ||
| 130 | crc = (crc >> 1) ^ @intFromEnum(poly); | ||
| 131 | } else { | ||
| 132 | crc = (crc >> 1); | ||
| 133 | } | ||
| 134 | } | ||
| 135 | e.* = crc; | ||
| 136 | } | ||
| 137 | |||
| 138 | var i: usize = 0; | ||
| 139 | while (i < 256) : (i += 1) { | ||
| 140 | var crc = tables[0][i]; | ||
| 141 | var j: usize = 1; | ||
| 142 | while (j < 8) : (j += 1) { | ||
| 143 | const index: u8 = @truncate(crc); | ||
| 144 | crc = tables[0][index] ^ (crc >> 8); | ||
| 145 | tables[j][i] = crc; | ||
| 146 | } | ||
| 147 | } | ||
| 148 | |||
| 149 | break :block tables; | ||
| 150 | }; | ||
| 151 | |||
| 152 | crc: u32, | ||
| 153 | |||
| 154 | pub fn init() Self { | ||
| 155 | return Self{ .crc = 0xffffffff }; | ||
| 156 | } | ||
| 157 | |||
| 158 | pub fn update(self: *Self, input: []const u8) void { | ||
| 159 | var i: usize = 0; | ||
| 160 | while (i + 8 <= input.len) : (i += 8) { | ||
| 161 | const p = input[i..][0..8]; | ||
| 162 | |||
| 163 | // Unrolling this way gives ~50Mb/s increase | ||
| 164 | self.crc ^= std.mem.readInt(u32, p[0..4], .little); | ||
| 165 | |||
| 166 | self.crc = | ||
| 167 | lookup_tables[0][p[7]] ^ | ||
| 168 | lookup_tables[1][p[6]] ^ | ||
| 169 | lookup_tables[2][p[5]] ^ | ||
| 170 | lookup_tables[3][p[4]] ^ | ||
| 171 | lookup_tables[4][@as(u8, @truncate(self.crc >> 24))] ^ | ||
| 172 | lookup_tables[5][@as(u8, @truncate(self.crc >> 16))] ^ | ||
| 173 | lookup_tables[6][@as(u8, @truncate(self.crc >> 8))] ^ | ||
| 174 | lookup_tables[7][@as(u8, @truncate(self.crc >> 0))]; | ||
| 175 | } | ||
| 176 | |||
| 177 | while (i < input.len) : (i += 1) { | ||
| 178 | const index = @as(u8, @truncate(self.crc)) ^ input[i]; | ||
| 179 | self.crc = (self.crc >> 8) ^ lookup_tables[0][index]; | ||
| 180 | } | ||
| 181 | } | ||
| 182 | |||
| 183 | pub fn final(self: *Self) u32 { | ||
| 184 | return ~self.crc; | ||
| 185 | } | ||
| 186 | |||
| 187 | pub fn hash(input: []const u8) u32 { | ||
| 188 | var c = Self.init(); | ||
| 189 | c.update(input); | ||
| 190 | return c.final(); | ||
| 191 | } | ||
| 192 | }; | ||
| 193 | } | ||
| 194 | |||
| 195 | // half-byte lookup table implementation. | ||
| 196 | pub fn Crc32SmallWithPoly(comptime poly: Polynomial) type { | ||
| 197 | return struct { | ||
| 198 | const Self = @This(); | ||
| 199 | const lookup_table = block: { | ||
| 200 | var table: [16]u32 = undefined; | ||
| 201 | |||
| 202 | for (&table, 0..) |*e, i| { | ||
| 203 | var crc = @as(u32, @intCast(i * 16)); | ||
| 204 | var j: usize = 0; | ||
| 205 | while (j < 8) : (j += 1) { | ||
| 206 | if (crc & 1 == 1) { | ||
| 207 | crc = (crc >> 1) ^ @intFromEnum(poly); | ||
| 208 | } else { | ||
| 209 | crc = (crc >> 1); | ||
| 210 | } | ||
| 211 | } | ||
| 212 | e.* = crc; | ||
| 213 | } | ||
| 214 | |||
| 215 | break :block table; | ||
| 216 | }; | ||
| 217 | |||
| 218 | crc: u32, | ||
| 219 | |||
| 220 | pub fn init() Self { | ||
| 221 | return Self{ .crc = 0xffffffff }; | ||
| 222 | } | ||
| 223 | |||
| 224 | pub fn update(self: *Self, input: []const u8) void { | ||
| 225 | for (input) |b| { | ||
| 226 | self.crc = lookup_table[@as(u4, @truncate(self.crc ^ (b >> 0)))] ^ (self.crc >> 4); | ||
| 227 | self.crc = lookup_table[@as(u4, @truncate(self.crc ^ (b >> 4)))] ^ (self.crc >> 4); | ||
| 228 | } | ||
| 229 | } | ||
| 230 | |||
| 231 | pub fn final(self: *Self) u32 { | ||
| 232 | return ~self.crc; | ||
| 233 | } | ||
| 234 | |||
| 235 | pub fn hash(input: []const u8) u32 { | ||
| 236 | var c = Self.init(); | ||
| 237 | c.update(input); | ||
| 238 | return c.final(); | ||
| 239 | } | ||
| 240 | }; | ||
| 241 | } |
lib/std/hash/crc/test.zig+28-14| ... | @@ -5,22 +5,25 @@ const testing = std.testing; | ... | @@ -5,22 +5,25 @@ const testing = std.testing; |
| 5 | const verify = @import("../verify.zig"); | 5 | const verify = @import("../verify.zig"); |
| 6 | const crc = @import("../crc.zig"); | 6 | const crc = @import("../crc.zig"); |
| 7 | 7 | ||
| 8 | test "crc32 ieee" { | 8 | test "crc32 ieee regression" { |
| 9 | inline for ([2]type{ crc.Crc32WithPoly(.IEEE), crc.Crc32SmallWithPoly(.IEEE) }) |ieee| { | 9 | const crc32 = crc.Crc32IsoHdlc; |
| 10 | try testing.expect(ieee.hash("") == 0x00000000); | 10 | try testing.expectEqual(crc32.hash(""), 0x00000000); |
| 11 | try testing.expect(ieee.hash("a") == 0xe8b7be43); | 11 | try testing.expectEqual(crc32.hash("a"), 0xe8b7be43); |
| 12 | try testing.expect(ieee.hash("abc") == 0x352441c2); | 12 | try testing.expectEqual(crc32.hash("abc"), 0x352441c2); |
| 13 | try verify.iterativeApi(ieee); | ||
| 14 | } | ||
| 15 | } | 13 | } |
| 16 | 14 | ||
| 17 | test "crc32 castagnoli" { | 15 | test "crc32 castagnoli regression" { |
| 18 | inline for ([2]type{ crc.Crc32WithPoly(.Castagnoli), crc.Crc32SmallWithPoly(.Castagnoli) }) |casta| { | 16 | const crc32 = crc.Crc32Iscsi; |
| 19 | try testing.expect(casta.hash("") == 0x00000000); | 17 | try testing.expectEqual(crc32.hash(""), 0x00000000); |
| 20 | try testing.expect(casta.hash("a") == 0xc1d04330); | 18 | try testing.expectEqual(crc32.hash("a"), 0xc1d04330); |
| 21 | try testing.expect(casta.hash("abc") == 0x364b3fb7); | 19 | try testing.expectEqual(crc32.hash("abc"), 0x364b3fb7); |
| 22 | try verify.iterativeApi(casta); | 20 | } |
| 23 | } | 21 | |
| 22 | test "crc32 koopman regression" { | ||
| 23 | const crc32 = crc.Crc32Koopman; | ||
| 24 | try testing.expectEqual(crc32.hash(""), 0x00000000); | ||
| 25 | try testing.expectEqual(crc32.hash("a"), 0x0da2aa8a); | ||
| 26 | try testing.expectEqual(crc32.hash("abc"), 0xba2322ac); | ||
| 24 | } | 27 | } |
| 25 | 28 | ||
| 26 | test "CRC-3/GSM" { | 29 | test "CRC-3/GSM" { |
| ... | @@ -1134,6 +1137,17 @@ test "CRC-32/JAMCRC" { | ... | @@ -1134,6 +1137,17 @@ test "CRC-32/JAMCRC" { |
| 1134 | try testing.expectEqual(@as(u32, 0x340bc6d9), c.final()); | 1137 | try testing.expectEqual(@as(u32, 0x340bc6d9), c.final()); |
| 1135 | } | 1138 | } |
| 1136 | 1139 | ||
| 1140 | test "CRC-32/KOOPMAN" { | ||
| 1141 | const Crc32Koopman = crc.Crc32Koopman; | ||
| 1142 | |||
| 1143 | try testing.expectEqual(@as(u32, 0x2d3dd0ae), Crc32Koopman.hash("123456789")); | ||
| 1144 | |||
| 1145 | var c = Crc32Koopman.init(); | ||
| 1146 | c.update("1234"); | ||
| 1147 | c.update("56789"); | ||
| 1148 | try testing.expectEqual(@as(u32, 0x2d3dd0ae), c.final()); | ||
| 1149 | } | ||
| 1150 | |||
| 1137 | test "CRC-32/MEF" { | 1151 | test "CRC-32/MEF" { |
| 1138 | const Crc32Mef = crc.Crc32Mef; | 1152 | const Crc32Mef = crc.Crc32Mef; |
| 1139 | 1153 |
tools/crc/catalog.txt+1| ... | @@ -100,6 +100,7 @@ width=32 poly=0x04c11db7 init=0x00000000 refin=false refout=false xorout=0x | ... | @@ -100,6 +100,7 @@ width=32 poly=0x04c11db7 init=0x00000000 refin=false refout=false xorout=0x |
| 100 | width=32 poly=0x1edc6f41 init=0xffffffff refin=true refout=true xorout=0xffffffff check=0xe3069283 residue=0xb798b438 name="CRC-32/ISCSI" | 100 | width=32 poly=0x1edc6f41 init=0xffffffff refin=true refout=true xorout=0xffffffff check=0xe3069283 residue=0xb798b438 name="CRC-32/ISCSI" |
| 101 | width=32 poly=0x04c11db7 init=0xffffffff refin=true refout=true xorout=0xffffffff check=0xcbf43926 residue=0xdebb20e3 name="CRC-32/ISO-HDLC" | 101 | width=32 poly=0x04c11db7 init=0xffffffff refin=true refout=true xorout=0xffffffff check=0xcbf43926 residue=0xdebb20e3 name="CRC-32/ISO-HDLC" |
| 102 | width=32 poly=0x04c11db7 init=0xffffffff refin=true refout=true xorout=0x00000000 check=0x340bc6d9 residue=0x00000000 name="CRC-32/JAMCRC" | 102 | width=32 poly=0x04c11db7 init=0xffffffff refin=true refout=true xorout=0x00000000 check=0x340bc6d9 residue=0x00000000 name="CRC-32/JAMCRC" |
| 103 | width=32 poly=0x741b8cd7 init=0xffffffff refin=true refout=true xorout=0xffffffff check=0x2d3dd0ae residue=0x00000000 name="CRC-32/KOOPMAN" | ||
| 103 | width=32 poly=0x741b8cd7 init=0xffffffff refin=true refout=true xorout=0x00000000 check=0xd2c22f51 residue=0x00000000 name="CRC-32/MEF" | 104 | width=32 poly=0x741b8cd7 init=0xffffffff refin=true refout=true xorout=0x00000000 check=0xd2c22f51 residue=0x00000000 name="CRC-32/MEF" |
| 104 | width=32 poly=0x04c11db7 init=0xffffffff refin=false refout=false xorout=0x00000000 check=0x0376e6e7 residue=0x00000000 name="CRC-32/MPEG-2" | 105 | width=32 poly=0x04c11db7 init=0xffffffff refin=false refout=false xorout=0x00000000 check=0x0376e6e7 residue=0x00000000 name="CRC-32/MPEG-2" |
| 105 | width=32 poly=0x000000af init=0x00000000 refin=false refout=false xorout=0x00000000 check=0xbd0be338 residue=0x00000000 name="CRC-32/XFER" | 106 | width=32 poly=0x000000af init=0x00000000 refin=false refout=false xorout=0x00000000 check=0xbd0be338 residue=0x00000000 name="CRC-32/XFER" |
tools/update_crc_catalog.zig+18-16| ... | @@ -48,8 +48,7 @@ pub fn main() anyerror!void { | ... | @@ -48,8 +48,7 @@ pub fn main() anyerror!void { |
| 48 | \\pub const Crc32WithPoly = impl.Crc32WithPoly; | 48 | \\pub const Crc32WithPoly = impl.Crc32WithPoly; |
| 49 | \\pub const Crc32SmallWithPoly = impl.Crc32SmallWithPoly; | 49 | \\pub const Crc32SmallWithPoly = impl.Crc32SmallWithPoly; |
| 50 | \\ | 50 | \\ |
| 51 | \\// IEEE is by far the most common CRC and so is aliased by default. | 51 | \\pub const Crc32 = Crc32IsoHdlc; |
| 52 | \\pub const Crc32 = Crc32WithPoly(.IEEE); | ||
| 53 | \\ | 52 | \\ |
| 54 | \\test { | 53 | \\test { |
| 55 | \\ _ = @import("crc/test.zig"); | 54 | \\ _ = @import("crc/test.zig"); |
| ... | @@ -72,22 +71,25 @@ pub fn main() anyerror!void { | ... | @@ -72,22 +71,25 @@ pub fn main() anyerror!void { |
| 72 | \\const verify = @import("../verify.zig"); | 71 | \\const verify = @import("../verify.zig"); |
| 73 | \\const crc = @import("../crc.zig"); | 72 | \\const crc = @import("../crc.zig"); |
| 74 | \\ | 73 | \\ |
| 75 | \\test "crc32 ieee" { | 74 | \\test "crc32 ieee regression" { |
| 76 | \\ inline for ([2]type{ crc.Crc32WithPoly(.IEEE), crc.Crc32SmallWithPoly(.IEEE) }) |ieee| { | 75 | \\ const crc32 = crc.Crc32IsoHdlc; |
| 77 | \\ try testing.expect(ieee.hash("") == 0x00000000); | 76 | \\ try testing.expectEqual(crc32.hash(""), 0x00000000); |
| 78 | \\ try testing.expect(ieee.hash("a") == 0xe8b7be43); | 77 | \\ try testing.expectEqual(crc32.hash("a"), 0xe8b7be43); |
| 79 | \\ try testing.expect(ieee.hash("abc") == 0x352441c2); | 78 | \\ try testing.expectEqual(crc32.hash("abc"), 0x352441c2); |
| 80 | \\ try verify.iterativeApi(ieee); | ||
| 81 | \\ } | ||
| 82 | \\} | 79 | \\} |
| 83 | \\ | 80 | \\ |
| 84 | \\test "crc32 castagnoli" { | 81 | \\test "crc32 castagnoli regression" { |
| 85 | \\ inline for ([2]type{ crc.Crc32WithPoly(.Castagnoli), crc.Crc32SmallWithPoly(.Castagnoli) }) |casta| { | 82 | \\ const crc32 = crc.Crc32Iscsi; |
| 86 | \\ try testing.expect(casta.hash("") == 0x00000000); | 83 | \\ try testing.expectEqual(crc32.hash(""), 0x00000000); |
| 87 | \\ try testing.expect(casta.hash("a") == 0xc1d04330); | 84 | \\ try testing.expectEqual(crc32.hash("a"), 0xc1d04330); |
| 88 | \\ try testing.expect(casta.hash("abc") == 0x364b3fb7); | 85 | \\ try testing.expectEqual(crc32.hash("abc"), 0x364b3fb7); |
| 89 | \\ try verify.iterativeApi(casta); | 86 | \\} |
| 90 | \\ } | 87 | \\ |
| 88 | \\test "crc32 koopman regression" { | ||
| 89 | \\ const crc32 = crc.Koopman; | ||
| 90 | \\ try testing.expectEqual(crc32.hash(""), 0x00000000); | ||
| 91 | \\ try testing.expectEqual(crc32.hash("a"), 0x0da2aa8a); | ||
| 92 | \\ try testing.expectEqual(crc32.hash("abc"), 0xba2322ac); | ||
| 91 | \\} | 93 | \\} |
| 92 | \\ | 94 | \\ |
| 93 | ); | 95 | ); |