From d555994960d532c4b829421176e1f50efe0ac37a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Motiejus=20Jak=C5=A1tys?= Date: Wed, 23 Feb 2022 06:47:56 +0200 Subject: [PATCH] wip varint --- src/test_main.zig | 1 + src/varint.zig | 90 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+) create mode 100644 src/varint.zig diff --git a/src/test_main.zig b/src/test_main.zig index 2b9594e..8aa20ff 100644 --- a/src/test_main.zig +++ b/src/test_main.zig @@ -5,4 +5,5 @@ test "turbonss test suite" { _ = @import("user.zig"); _ = @import("group.zig"); _ = @import("padding.zig"); + _ = @import("varint.zig"); } diff --git a/src/varint.zig b/src/varint.zig new file mode 100644 index 0000000..7a4420c --- /dev/null +++ b/src/varint.zig @@ -0,0 +1,90 @@ +// +// varint64 []const u8 variants +// +// Thanks to https://github.com/gsquire/zig-snappy/blob/master/snappy.zig and golang's +// varint implementation. + +const std = @import("std"); + +// Represents a variable length integer that we read from a byte stream along +// with how many bytes were read to decode it. +pub const Varint = struct { + value: u64, + bytesRead: usize, +}; + +const MaxVarintLen64 = 10; + +// https://golang.org/pkg/encoding/binary/#Uvarint +pub fn uvarint(buf: []const u8) error{Overflow}!Varint { + var x: u64 = 0; + var s: u6 = 0; + + for (buf) |b, i| { + if (i == MaxVarintLen64) { + // Catch byte reads past MaxVarintLen64. + // See issue https://golang.org/issues/41185 + return error.Overflow; + } + + if (b < 0x80) { + if (i == MaxVarintLen64 - 1 and b > 1) { + return error.Overflow; + } + return Varint{ .value = x | (@as(u64, b) << s), .bytesRead = i + 1 }; + } + x |= (@as(u64, b & 0x7f) << s); + s += 7; + } + + return Varint{ + .value = 0, + .bytesRead = 0, + }; +} + +// https://golang.org/pkg/encoding/binary/#PutUvarint +pub fn putUvarint(buf: []u8, x: u64) usize { + var i: usize = 0; + var mutX = x; + + while (mutX >= 0x80) { + buf[i] = @truncate(u8, mutX) | 0x80; + mutX >>= 7; + i += 1; + } + buf[i] = @truncate(u8, mutX); + + return i + 1; +} + +const testing = std.testing; + +const tests = [_]u64{ + 0, + 1, + 2, + 10, + 20, + 63, + 64, + 65, + 127, + 128, + 129, + 255, + 256, + 257, + 1 << 63 - 1, +}; + +test "uvarint" { + for (tests) |x| { + var buf: [MaxVarintLen64]u8 = undefined; + const n = putUvarint(buf[0..], x); + const got = try uvarint(buf[0..n]); + + try testing.expectEqual(x, got.value); + try testing.expectEqual(n, got.bytesRead); + } +}