union Table [src]

Fields

fse: []const Fse
rle: u8

Members

Source

pub const Table = union(enum) { fse: []const Fse, rle: u8, pub const Fse = struct { symbol: u8, baseline: u16, bits: u8, }; pub fn decode( bit_reader: *BitReader, expected_symbol_count: usize, max_accuracy_log: u4, entries: []Table.Fse, ) !usize { const accuracy_log_biased = try bit_reader.readBitsNoEof(u4, 4); if (accuracy_log_biased > max_accuracy_log -| 5) return error.MalformedAccuracyLog; const accuracy_log = accuracy_log_biased + 5; var values: [256]u16 = undefined; var value_count: usize = 0; const total_probability = @as(u16, 1) << accuracy_log; var accumulated_probability: u16 = 0; while (accumulated_probability < total_probability) { // WARNING: The RFC is poorly worded, and would suggest std.math.log2_int_ceil is correct here, // but power of two (remaining probabilities + 1) need max bits set to 1 more. const max_bits = std.math.log2_int(u16, total_probability - accumulated_probability + 1) + 1; const small = try bit_reader.readBitsNoEof(u16, max_bits - 1); const cutoff = (@as(u16, 1) << max_bits) - 1 - (total_probability - accumulated_probability + 1); const value = if (small < cutoff) small else value: { const value_read = small + (try bit_reader.readBitsNoEof(u16, 1) << (max_bits - 1)); break :value if (value_read < @as(u16, 1) << (max_bits - 1)) value_read else value_read - cutoff; }; accumulated_probability += if (value != 0) value - 1 else 1; values[value_count] = value; value_count += 1; if (value == 1) { while (true) { const repeat_flag = try bit_reader.readBitsNoEof(u2, 2); if (repeat_flag + value_count > 256) return error.MalformedFseTable; for (0..repeat_flag) |_| { values[value_count] = 1; value_count += 1; } if (repeat_flag < 3) break; } } if (value_count == 256) break; } bit_reader.alignToByte(); if (value_count < 2) return error.MalformedFseTable; if (accumulated_probability != total_probability) return error.MalformedFseTable; if (value_count > expected_symbol_count) return error.MalformedFseTable; const table_size = total_probability; try build(values[0..value_count], entries[0..table_size]); return table_size; } pub fn build(values: []const u16, entries: []Table.Fse) !void { const total_probability = @as(u16, @intCast(entries.len)); const accuracy_log = std.math.log2_int(u16, total_probability); assert(total_probability <= 1 << 9); var less_than_one_count: usize = 0; for (values, 0..) |value, i| { if (value == 0) { entries[entries.len - 1 - less_than_one_count] = Table.Fse{ .symbol = @as(u8, @intCast(i)), .baseline = 0, .bits = accuracy_log, }; less_than_one_count += 1; } } var position: usize = 0; var temp_states: [1 << 9]u16 = undefined; for (values, 0..) |value, symbol| { if (value == 0 or value == 1) continue; const probability = value - 1; const state_share_dividend = std.math.ceilPowerOfTwo(u16, probability) catch return error.MalformedFseTable; const share_size = @divExact(total_probability, state_share_dividend); const double_state_count = state_share_dividend - probability; const single_state_count = probability - double_state_count; const share_size_log = std.math.log2_int(u16, share_size); for (0..probability) |i| { temp_states[i] = @as(u16, @intCast(position)); position += (entries.len >> 1) + (entries.len >> 3) + 3; position &= entries.len - 1; while (position >= entries.len - less_than_one_count) { position += (entries.len >> 1) + (entries.len >> 3) + 3; position &= entries.len - 1; } } std.mem.sort(u16, temp_states[0..probability], {}, std.sort.asc(u16)); for (0..probability) |i| { entries[temp_states[i]] = if (i < double_state_count) Table.Fse{ .symbol = @as(u8, @intCast(symbol)), .bits = share_size_log + 1, .baseline = single_state_count * share_size + @as(u16, @intCast(i)) * 2 * share_size, } else Table.Fse{ .symbol = @as(u8, @intCast(symbol)), .bits = share_size_log, .baseline = (@as(u16, @intCast(i)) - double_state_count) * share_size, }; } } } test build { const literals_length_default_values = [36]u16{ 5, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 2, 2, 2, 2, 2, 0, 0, 0, 0, }; const match_lengths_default_values = [53]u16{ 2, 5, 4, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, }; const offset_codes_default_values = [29]u16{ 2, 2, 2, 2, 2, 2, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, }; var entries: [64]Table.Fse = undefined; try build(&literals_length_default_values, &entries); try std.testing.expectEqualSlices(Table.Fse, Table.predefined_literal.fse, &entries); try build(&match_lengths_default_values, &entries); try std.testing.expectEqualSlices(Table.Fse, Table.predefined_match.fse, &entries); try build(&offset_codes_default_values, entries[0..32]); try std.testing.expectEqualSlices(Table.Fse, Table.predefined_offset.fse, entries[0..32]); } pub const predefined_literal: Table = .{ .fse = &[64]Table.Fse{ .{ .symbol = 0, .bits = 4, .baseline = 0 }, .{ .symbol = 0, .bits = 4, .baseline = 16 }, .{ .symbol = 1, .bits = 5, .baseline = 32 }, .{ .symbol = 3, .bits = 5, .baseline = 0 }, .{ .symbol = 4, .bits = 5, .baseline = 0 }, .{ .symbol = 6, .bits = 5, .baseline = 0 }, .{ .symbol = 7, .bits = 5, .baseline = 0 }, .{ .symbol = 9, .bits = 5, .baseline = 0 }, .{ .symbol = 10, .bits = 5, .baseline = 0 }, .{ .symbol = 12, .bits = 5, .baseline = 0 }, .{ .symbol = 14, .bits = 6, .baseline = 0 }, .{ .symbol = 16, .bits = 5, .baseline = 0 }, .{ .symbol = 18, .bits = 5, .baseline = 0 }, .{ .symbol = 19, .bits = 5, .baseline = 0 }, .{ .symbol = 21, .bits = 5, .baseline = 0 }, .{ .symbol = 22, .bits = 5, .baseline = 0 }, .{ .symbol = 24, .bits = 5, .baseline = 0 }, .{ .symbol = 25, .bits = 5, .baseline = 32 }, .{ .symbol = 26, .bits = 5, .baseline = 0 }, .{ .symbol = 27, .bits = 6, .baseline = 0 }, .{ .symbol = 29, .bits = 6, .baseline = 0 }, .{ .symbol = 31, .bits = 6, .baseline = 0 }, .{ .symbol = 0, .bits = 4, .baseline = 32 }, .{ .symbol = 1, .bits = 4, .baseline = 0 }, .{ .symbol = 2, .bits = 5, .baseline = 0 }, .{ .symbol = 4, .bits = 5, .baseline = 32 }, .{ .symbol = 5, .bits = 5, .baseline = 0 }, .{ .symbol = 7, .bits = 5, .baseline = 32 }, .{ .symbol = 8, .bits = 5, .baseline = 0 }, .{ .symbol = 10, .bits = 5, .baseline = 32 }, .{ .symbol = 11, .bits = 5, .baseline = 0 }, .{ .symbol = 13, .bits = 6, .baseline = 0 }, .{ .symbol = 16, .bits = 5, .baseline = 32 }, .{ .symbol = 17, .bits = 5, .baseline = 0 }, .{ .symbol = 19, .bits = 5, .baseline = 32 }, .{ .symbol = 20, .bits = 5, .baseline = 0 }, .{ .symbol = 22, .bits = 5, .baseline = 32 }, .{ .symbol = 23, .bits = 5, .baseline = 0 }, .{ .symbol = 25, .bits = 4, .baseline = 0 }, .{ .symbol = 25, .bits = 4, .baseline = 16 }, .{ .symbol = 26, .bits = 5, .baseline = 32 }, .{ .symbol = 28, .bits = 6, .baseline = 0 }, .{ .symbol = 30, .bits = 6, .baseline = 0 }, .{ .symbol = 0, .bits = 4, .baseline = 48 }, .{ .symbol = 1, .bits = 4, .baseline = 16 }, .{ .symbol = 2, .bits = 5, .baseline = 32 }, .{ .symbol = 3, .bits = 5, .baseline = 32 }, .{ .symbol = 5, .bits = 5, .baseline = 32 }, .{ .symbol = 6, .bits = 5, .baseline = 32 }, .{ .symbol = 8, .bits = 5, .baseline = 32 }, .{ .symbol = 9, .bits = 5, .baseline = 32 }, .{ .symbol = 11, .bits = 5, .baseline = 32 }, .{ .symbol = 12, .bits = 5, .baseline = 32 }, .{ .symbol = 15, .bits = 6, .baseline = 0 }, .{ .symbol = 17, .bits = 5, .baseline = 32 }, .{ .symbol = 18, .bits = 5, .baseline = 32 }, .{ .symbol = 20, .bits = 5, .baseline = 32 }, .{ .symbol = 21, .bits = 5, .baseline = 32 }, .{ .symbol = 23, .bits = 5, .baseline = 32 }, .{ .symbol = 24, .bits = 5, .baseline = 32 }, .{ .symbol = 35, .bits = 6, .baseline = 0 }, .{ .symbol = 34, .bits = 6, .baseline = 0 }, .{ .symbol = 33, .bits = 6, .baseline = 0 }, .{ .symbol = 32, .bits = 6, .baseline = 0 }, }, }; pub const predefined_match: Table = .{ .fse = &[64]Table.Fse{ .{ .symbol = 0, .bits = 6, .baseline = 0 }, .{ .symbol = 1, .bits = 4, .baseline = 0 }, .{ .symbol = 2, .bits = 5, .baseline = 32 }, .{ .symbol = 3, .bits = 5, .baseline = 0 }, .{ .symbol = 5, .bits = 5, .baseline = 0 }, .{ .symbol = 6, .bits = 5, .baseline = 0 }, .{ .symbol = 8, .bits = 5, .baseline = 0 }, .{ .symbol = 10, .bits = 6, .baseline = 0 }, .{ .symbol = 13, .bits = 6, .baseline = 0 }, .{ .symbol = 16, .bits = 6, .baseline = 0 }, .{ .symbol = 19, .bits = 6, .baseline = 0 }, .{ .symbol = 22, .bits = 6, .baseline = 0 }, .{ .symbol = 25, .bits = 6, .baseline = 0 }, .{ .symbol = 28, .bits = 6, .baseline = 0 }, .{ .symbol = 31, .bits = 6, .baseline = 0 }, .{ .symbol = 33, .bits = 6, .baseline = 0 }, .{ .symbol = 35, .bits = 6, .baseline = 0 }, .{ .symbol = 37, .bits = 6, .baseline = 0 }, .{ .symbol = 39, .bits = 6, .baseline = 0 }, .{ .symbol = 41, .bits = 6, .baseline = 0 }, .{ .symbol = 43, .bits = 6, .baseline = 0 }, .{ .symbol = 45, .bits = 6, .baseline = 0 }, .{ .symbol = 1, .bits = 4, .baseline = 16 }, .{ .symbol = 2, .bits = 4, .baseline = 0 }, .{ .symbol = 3, .bits = 5, .baseline = 32 }, .{ .symbol = 4, .bits = 5, .baseline = 0 }, .{ .symbol = 6, .bits = 5, .baseline = 32 }, .{ .symbol = 7, .bits = 5, .baseline = 0 }, .{ .symbol = 9, .bits = 6, .baseline = 0 }, .{ .symbol = 12, .bits = 6, .baseline = 0 }, .{ .symbol = 15, .bits = 6, .baseline = 0 }, .{ .symbol = 18, .bits = 6, .baseline = 0 }, .{ .symbol = 21, .bits = 6, .baseline = 0 }, .{ .symbol = 24, .bits = 6, .baseline = 0 }, .{ .symbol = 27, .bits = 6, .baseline = 0 }, .{ .symbol = 30, .bits = 6, .baseline = 0 }, .{ .symbol = 32, .bits = 6, .baseline = 0 }, .{ .symbol = 34, .bits = 6, .baseline = 0 }, .{ .symbol = 36, .bits = 6, .baseline = 0 }, .{ .symbol = 38, .bits = 6, .baseline = 0 }, .{ .symbol = 40, .bits = 6, .baseline = 0 }, .{ .symbol = 42, .bits = 6, .baseline = 0 }, .{ .symbol = 44, .bits = 6, .baseline = 0 }, .{ .symbol = 1, .bits = 4, .baseline = 32 }, .{ .symbol = 1, .bits = 4, .baseline = 48 }, .{ .symbol = 2, .bits = 4, .baseline = 16 }, .{ .symbol = 4, .bits = 5, .baseline = 32 }, .{ .symbol = 5, .bits = 5, .baseline = 32 }, .{ .symbol = 7, .bits = 5, .baseline = 32 }, .{ .symbol = 8, .bits = 5, .baseline = 32 }, .{ .symbol = 11, .bits = 6, .baseline = 0 }, .{ .symbol = 14, .bits = 6, .baseline = 0 }, .{ .symbol = 17, .bits = 6, .baseline = 0 }, .{ .symbol = 20, .bits = 6, .baseline = 0 }, .{ .symbol = 23, .bits = 6, .baseline = 0 }, .{ .symbol = 26, .bits = 6, .baseline = 0 }, .{ .symbol = 29, .bits = 6, .baseline = 0 }, .{ .symbol = 52, .bits = 6, .baseline = 0 }, .{ .symbol = 51, .bits = 6, .baseline = 0 }, .{ .symbol = 50, .bits = 6, .baseline = 0 }, .{ .symbol = 49, .bits = 6, .baseline = 0 }, .{ .symbol = 48, .bits = 6, .baseline = 0 }, .{ .symbol = 47, .bits = 6, .baseline = 0 }, .{ .symbol = 46, .bits = 6, .baseline = 0 }, }, }; pub const predefined_offset: Table = .{ .fse = &[32]Table.Fse{ .{ .symbol = 0, .bits = 5, .baseline = 0 }, .{ .symbol = 6, .bits = 4, .baseline = 0 }, .{ .symbol = 9, .bits = 5, .baseline = 0 }, .{ .symbol = 15, .bits = 5, .baseline = 0 }, .{ .symbol = 21, .bits = 5, .baseline = 0 }, .{ .symbol = 3, .bits = 5, .baseline = 0 }, .{ .symbol = 7, .bits = 4, .baseline = 0 }, .{ .symbol = 12, .bits = 5, .baseline = 0 }, .{ .symbol = 18, .bits = 5, .baseline = 0 }, .{ .symbol = 23, .bits = 5, .baseline = 0 }, .{ .symbol = 5, .bits = 5, .baseline = 0 }, .{ .symbol = 8, .bits = 4, .baseline = 0 }, .{ .symbol = 14, .bits = 5, .baseline = 0 }, .{ .symbol = 20, .bits = 5, .baseline = 0 }, .{ .symbol = 2, .bits = 5, .baseline = 0 }, .{ .symbol = 7, .bits = 4, .baseline = 16 }, .{ .symbol = 11, .bits = 5, .baseline = 0 }, .{ .symbol = 17, .bits = 5, .baseline = 0 }, .{ .symbol = 22, .bits = 5, .baseline = 0 }, .{ .symbol = 4, .bits = 5, .baseline = 0 }, .{ .symbol = 8, .bits = 4, .baseline = 16 }, .{ .symbol = 13, .bits = 5, .baseline = 0 }, .{ .symbol = 19, .bits = 5, .baseline = 0 }, .{ .symbol = 1, .bits = 5, .baseline = 0 }, .{ .symbol = 6, .bits = 4, .baseline = 16 }, .{ .symbol = 10, .bits = 5, .baseline = 0 }, .{ .symbol = 16, .bits = 5, .baseline = 0 }, .{ .symbol = 28, .bits = 5, .baseline = 0 }, .{ .symbol = 27, .bits = 5, .baseline = 0 }, .{ .symbol = 26, .bits = 5, .baseline = 0 }, .{ .symbol = 25, .bits = 5, .baseline = 0 }, .{ .symbol = 24, .bits = 5, .baseline = 0 }, }, }; }