implement delta compression

This commit is contained in:
Motiejus Jakštys 2022-02-28 05:48:43 +02:00 committed by Motiejus Jakštys
parent df8ab1fbbf
commit ca67bf56e7

View File

@ -6,6 +6,60 @@
const std = @import("std"); const std = @import("std");
// delta compresses an incrementing sorted array of integers using delta
// compression. Sorting is in-place.
pub fn deltaCompress(comptime T: type, elems: []T) error{NotSorted}!void {
if (elems.len == 0) {
return;
}
var prev: T = elems[0];
var i: usize = 1;
while (i < elems.len) : (i += 1) {
const cur = elems[i];
if (cur <= prev) {
return error.NotSorted;
}
elems[i] = cur - prev - 1;
prev = cur;
}
}
const testing = std.testing;
test "delta compression positive tests" {
const tests = [_]struct { input: []const u8, want: []const u8 }{
.{ .input = &[_]u8{}, .want = &[_]u8{} },
.{ .input = &[_]u8{0}, .want = &[_]u8{0} },
.{ .input = &[_]u8{10}, .want = &[_]u8{10} },
.{ .input = &[_]u8{ 0, 1, 2 }, .want = &[_]u8{ 0, 0, 0 } },
.{ .input = &[_]u8{ 0, 254, 255 }, .want = &[_]u8{ 0, 253, 0 } },
};
for (tests) |t| {
var arr = try std.ArrayList(u8).initCapacity(
testing.allocator,
t.input.len,
);
defer arr.deinit();
try arr.appendSlice(t.input);
try deltaCompress(u8, arr.items);
try testing.expectEqualSlices(u8, arr.items, t.want);
}
}
test "delta compression negative tests" {
for ([_][]const u8{
&[_]u8{ 0, 0 },
&[_]u8{ 0, 1, 1 },
&[_]u8{ 0, 1, 2, 1 },
}) |t| {
var arr = try std.ArrayList(u8).initCapacity(testing.allocator, t.len);
defer arr.deinit();
try arr.appendSlice(t);
try testing.expectError(error.NotSorted, deltaCompress(u8, arr.items));
}
}
// Represents a variable length integer that we read from a byte stream along // Represents a variable length integer that we read from a byte stream along
// with how many bytes were read to decode it. // with how many bytes were read to decode it.
pub const Varint = struct { pub const Varint = struct {
@ -58,9 +112,8 @@ pub fn putUvarint(buf: []u8, x: u64) usize {
return i + 1; return i + 1;
} }
const testing = std.testing; test "uvarint" {
const uvarint_tests = [_]u64{
const tests = [_]u64{
0, 0,
1, 1,
2, 2,
@ -76,10 +129,8 @@ const tests = [_]u64{
256, 256,
257, 257,
1 << 63 - 1, 1 << 63 - 1,
}; };
for (uvarint_tests) |x| {
test "uvarint" {
for (tests) |x| {
var buf: [maxVarintLen64]u8 = undefined; var buf: [maxVarintLen64]u8 = undefined;
const n = putUvarint(buf[0..], x); const n = putUvarint(buf[0..], x);
const got = try uvarint(buf[0..n]); const got = try uvarint(buf[0..n]);