fn checkFuzzedBuildFreqs(_: void, smith: *std.testing.Smith) !void {
@disableInstrumentation();
var freqs_limit: u16 = 65535;
var freqs_buf: [max_leafs]u16 = undefined;
var nfreqs: u15 = 0;
const incomplete_allowed = smith.value(bool);
while (nfreqs < @as(u8, @intFromBool(!incomplete_allowed)) + 1 or
nfreqs != freqs_buf.len and freqs_limit != 0 and
smith.eosWeightedSimple(15, 1))
{
const f = smith.valueWeighted(u16, &.{
.rangeAtMost(u16, 0, @min(31, freqs_limit), @max(freqs_limit, 1)),
.rangeAtMost(u16, 0, freqs_limit, 1),
});
freqs_buf[nfreqs] = f;
freqs_limit -= f;
nfreqs += 1;
}
var codes_buf: [max_leafs]u16 = undefined;
var bits_buf: [max_leafs]u4 = @splat(0);
const max_bits = smith.valueRangeAtMost(u4, math.log2_int_ceil(u15, nfreqs), 15);
const total_bits, const last_nonzero = build(
freqs_buf[0..nfreqs],
codes_buf[0..nfreqs],
bits_buf[0..nfreqs],
max_bits,
incomplete_allowed,
);
var has_bitlen_one: bool = false;
var expected_total_bits: u32 = 0;
var expected_last_nonzero: ?u16 = null;
var weighted_sum: u32 = 0;
for (freqs_buf[0..nfreqs], bits_buf[0..nfreqs], 0..) |f, nb, i| {
has_bitlen_one = has_bitlen_one or nb == 1;
weighted_sum += @shlExact(@as(u16, 1), 15 - nb) & ((1 << 15) - 1);
expected_total_bits += @as(u32, f) * nb;
if (nb != 0) expected_last_nonzero = @intCast(i);
}
errdefer std.log.err(
\\ incomplete_allowed: {}
\\ max_bits: {}
\\ freqs: {any}
\\ bits: {any}
\\ # freqs: {}
\\ weighted sum: {}
\\ has_bitlen_one: {}
\\ expected/actual total bits: {}/{}
\\ expected/actual last nonzero: {?}/{}
++ "\n", .{
incomplete_allowed,
max_bits,
freqs_buf[0..nfreqs],
bits_buf[0..nfreqs],
nfreqs,
weighted_sum,
has_bitlen_one,
expected_total_bits,
total_bits,
expected_last_nonzero,
last_nonzero,
});
try std.testing.expectEqual(expected_total_bits, total_bits);
try std.testing.expectEqual(expected_last_nonzero, last_nonzero);
if (weighted_sum > 1 << 15)
return error.OversubscribedHuffmanTree;
if (weighted_sum < 1 << 15 and
!(incomplete_allowed and has_bitlen_one and weighted_sum == 1 << 14))
return error.IncompleteHuffmanTree;
}