/* * Copyright (c) 2021, Idan Horowitz * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #pragma once namespace Compress { // RFC 1951 - 3.2.5 static constexpr struct { u16 symbol; u16 base_length; u16 extra_bits; } packed_length_symbols[29] = { { 257, 3, 0 }, { 258, 4, 0 }, { 259, 5, 0 }, { 260, 6, 0 }, { 261, 7, 0 }, { 262, 8, 0 }, { 263, 9, 0 }, { 264, 10, 0 }, { 265, 11, 1 }, { 266, 13, 1 }, { 267, 15, 1 }, { 268, 17, 1 }, { 269, 19, 2 }, { 270, 23, 2 }, { 271, 27, 2 }, { 272, 31, 2 }, { 273, 35, 3 }, { 274, 43, 3 }, { 275, 51, 3 }, { 276, 59, 3 }, { 277, 67, 4 }, { 278, 83, 4 }, { 279, 99, 4 }, { 280, 115, 4 }, { 281, 131, 5 }, { 282, 163, 5 }, { 283, 195, 5 }, { 284, 227, 5 }, { 285, 258, 0 } }; // RFC 1951 - 3.2.5 static constexpr struct { u16 symbol; u16 base_distance; u16 extra_bits; } packed_distances[31] = { { 0, 1, 0 }, { 1, 2, 0 }, { 2, 3, 0 }, { 3, 4, 0 }, { 4, 5, 1 }, { 5, 7, 1 }, { 6, 9, 2 }, { 7, 13, 2 }, { 8, 17, 3 }, { 9, 25, 3 }, { 10, 33, 4 }, { 11, 49, 4 }, { 12, 65, 5 }, { 13, 97, 5 }, { 14, 129, 6 }, { 15, 193, 6 }, { 16, 257, 7 }, { 17, 385, 7 }, { 18, 513, 8 }, { 19, 769, 8 }, { 20, 1025, 9 }, { 21, 1537, 9 }, { 22, 2049, 10 }, { 23, 3073, 10 }, { 24, 4097, 11 }, { 25, 6145, 11 }, { 26, 8193, 12 }, { 27, 12289, 12 }, { 28, 16385, 13 }, { 29, 24577, 13 }, { 30, 32 * KiB + 1, 0 }, // signifies end }; // RFC 1951 - 3.2.6 static constexpr struct { u16 base_value; u16 bits; } fixed_literal_bits[5] = { { 0, 8 }, { 144, 9 }, { 256, 7 }, { 280, 8 }, { 288, 0 } // signifies end }; // RFC 1951 - 3.2.7 static constexpr size_t code_lengths_code_lengths_order[] { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; static consteval Array generate_length_to_symbol() { Array array = { UINT16_MAX, UINT16_MAX, UINT16_MAX }; // there are 256 valid lengths (3-258) + 3 invalid lengths (0-2) size_t base_length = 0; for (size_t len = 3; len < 259; len++) { if (len == packed_length_symbols[base_length + 1].base_length) base_length++; array[len] = packed_length_symbols[base_length].symbol; } return array; }; static constexpr auto length_to_symbol = generate_length_to_symbol(); static consteval Array generate_distance_to_base_lo() { Array array; size_t base_distance = 0; for (size_t dist = 1; dist <= 256; dist++) { if (dist == packed_distances[base_distance + 1].base_distance) base_distance++; array[dist - 1] = packed_distances[base_distance].symbol; } return array; }; static constexpr auto distance_to_base_lo = generate_distance_to_base_lo(); static consteval Array generate_distance_to_base_hi() { Array array = { UINT16_MAX, UINT16_MAX }; size_t base_distance = 16; for (size_t dist = 257; dist <= 32 * KiB; dist++) { if (dist == packed_distances[base_distance + 1].base_distance) base_distance++; array[(dist - 1) >> 7] = packed_distances[base_distance].symbol; } return array; }; static constexpr auto distance_to_base_hi = generate_distance_to_base_hi(); static consteval Array generate_fixed_literal_bit_lengths() { Array array; for (size_t i = 0; i < 4; i++) { array.span().slice(fixed_literal_bits[i].base_value, fixed_literal_bits[i + 1].base_value - fixed_literal_bits[i].base_value).fill(fixed_literal_bits[i].bits); } return array; }; static constexpr auto fixed_literal_bit_lengths = generate_fixed_literal_bit_lengths(); static consteval Array generate_fixed_distance_bit_lengths() { Array array; array.fill(5); return array; }; static constexpr auto fixed_distance_bit_lengths = generate_fixed_distance_bit_lengths(); static consteval u8 reverse8(u8 value) { u8 result = 0; for (size_t i = 0; i < 8; i++) { if (value & (1 << i)) result |= 1 << (7 - i); } return result; } static consteval Array generate_reverse8_lookup_table() { Array array; for (size_t i = 0; i <= UINT8_MAX; i++) { array[i] = reverse8(i); } return array; } static constexpr auto reverse8_lookup_table = generate_reverse8_lookup_table(); // Lookup-table based bit swap ALWAYS_INLINE static u16 fast_reverse16(u16 value, size_t bits) { VERIFY(bits <= 16); u16 lo = value & 0xff; u16 hi = value >> 8; u16 reversed = (u16)((reverse8_lookup_table[lo] << 8) | reverse8_lookup_table[hi]); return reversed >> (16 - bits); } }