master
  1// There is a generic CRC implementation "Crc()" which can be parameterized via
  2// the Algorithm struct for a plethora of uses.
  3//
  4// The primary interface for all of the standard CRC algorithms is the
  5// generated file "crc.zig", which uses the implementation code here to define
  6// many standard CRCs.
  7
  8const std = @import("std");
  9
 10pub fn Algorithm(comptime W: type) type {
 11    return struct {
 12        polynomial: W,
 13        initial: W,
 14        reflect_input: bool,
 15        reflect_output: bool,
 16        xor_output: W,
 17    };
 18}
 19
 20pub fn Crc(comptime W: type, comptime algorithm: Algorithm(W)) type {
 21    return struct {
 22        const Self = @This();
 23        const I = if (@bitSizeOf(W) < 8) u8 else W;
 24        const lookup_table = blk: {
 25            @setEvalBranchQuota(2500);
 26
 27            const poly = if (algorithm.reflect_input)
 28                @bitReverse(@as(I, algorithm.polynomial)) >> (@bitSizeOf(I) - @bitSizeOf(W))
 29            else
 30                @as(I, algorithm.polynomial) << (@bitSizeOf(I) - @bitSizeOf(W));
 31
 32            var table: [256]I = undefined;
 33            for (&table, 0..) |*e, i| {
 34                var crc: I = i;
 35                if (algorithm.reflect_input) {
 36                    var j: usize = 0;
 37                    while (j < 8) : (j += 1) {
 38                        crc = (crc >> 1) ^ ((crc & 1) * poly);
 39                    }
 40                } else {
 41                    crc <<= @bitSizeOf(I) - 8;
 42                    var j: usize = 0;
 43                    while (j < 8) : (j += 1) {
 44                        crc = (crc << 1) ^ (((crc >> (@bitSizeOf(I) - 1)) & 1) * poly);
 45                    }
 46                }
 47                e.* = crc;
 48            }
 49            break :blk table;
 50        };
 51
 52        crc: I,
 53
 54        pub fn init() Self {
 55            const initial = if (algorithm.reflect_input)
 56                @bitReverse(@as(I, algorithm.initial)) >> (@bitSizeOf(I) - @bitSizeOf(W))
 57            else
 58                @as(I, algorithm.initial) << (@bitSizeOf(I) - @bitSizeOf(W));
 59            return Self{ .crc = initial };
 60        }
 61
 62        inline fn tableEntry(index: I) I {
 63            return lookup_table[@as(u8, @intCast(index & 0xFF))];
 64        }
 65
 66        pub fn update(self: *Self, bytes: []const u8) void {
 67            var i: usize = 0;
 68            if (@bitSizeOf(I) <= 8) {
 69                while (i < bytes.len) : (i += 1) {
 70                    self.crc = tableEntry(self.crc ^ bytes[i]);
 71                }
 72            } else if (algorithm.reflect_input) {
 73                while (i < bytes.len) : (i += 1) {
 74                    const table_index = self.crc ^ bytes[i];
 75                    self.crc = tableEntry(table_index) ^ (self.crc >> 8);
 76                }
 77            } else {
 78                while (i < bytes.len) : (i += 1) {
 79                    const table_index = (self.crc >> (@bitSizeOf(I) - 8)) ^ bytes[i];
 80                    self.crc = tableEntry(table_index) ^ (self.crc << 8);
 81                }
 82            }
 83        }
 84
 85        pub fn final(self: Self) W {
 86            var c = self.crc;
 87            if (algorithm.reflect_input != algorithm.reflect_output) {
 88                c = @bitReverse(c);
 89            }
 90            if (!algorithm.reflect_output) {
 91                c >>= @bitSizeOf(I) - @bitSizeOf(W);
 92            }
 93            return @as(W, @intCast(c ^ algorithm.xor_output));
 94        }
 95
 96        pub fn hash(bytes: []const u8) W {
 97            var c = Self.init();
 98            c.update(bytes);
 99            return c.final();
100        }
101    };
102}