const std = @import("std"); const Allocator = std.mem.Allocator; const bdz = @import("bdz.zig"); const c = @cImport({ @cInclude("cmph.h"); }); // pack packs cmph hashes for the given input and returns a slice ("cmph pack // minus first 4 bytes") for further storage. The slice must be freed by the // caller. const packErr = Allocator.Error || error{Overflow}; pub fn pack(allocator: Allocator, input: [][*:0]const u8) packErr![]const u8 { var cvector = @ptrCast([*c][*c]u8, input.ptr); const len = try std.math.cast(c_uint, input.len); var source = c.cmph_io_vector_adapter(cvector, len); defer c.cmph_io_vector_adapter_destroy(source); var config: *c.cmph_config_t = c.cmph_config_new(source) orelse return error.OutOfMemory; c.cmph_config_set_algo(config, c.CMPH_BDZ); c.cmph_config_set_b(config, 7); var hash: *c.cmph_t = c.cmph_new(config) orelse return error.OutOfMemory; c.cmph_config_destroy(config); const size = c.cmph_packed_size(hash); var buf = try allocator.alloc(u8, size); c.cmph_pack(hash, &buf[0]); c.cmph_destroy(hash); return buf[4..]; } const testing = std.testing; const items = .{ "aaaaaaaaaa", "bbbbbbbbbb", "cccccccccc", "dddddddddd", "eeeeeeeeee", "ffffffffff", "gggggggggg", "hhhhhhhhhh", "iiiiiiiiii", "jjjjjjjjjj", }; const items_len = items.len; fn samplePack(allocator: Allocator) ![]const u8 { var vector = std.ArrayList([*:0]const u8).init(allocator); defer vector.deinit(); try vector.appendSlice(&items); return pack(allocator, vector.items); } test "basic pack/unpack" { const buf = try samplePack(testing.allocator); defer testing.allocator.free(buf); try testing.expect(buf.len < 100); var used: [items_len]bool = undefined; inline for (items) |elem| { const hashed = try bdz.search(buf, elem); used[hashed] = true; } for (used) |item| { try testing.expect(item); } }