Skip to content

Commit

Permalink
extract parse_lit_or_len
Browse files Browse the repository at this point in the history
Change-Id: Ib2a9cccc5df211363b2083b01d46043b329cd025
  • Loading branch information
garymm committed Mar 10, 2024
1 parent 6983463 commit f5faa04
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 25 deletions.
72 changes: 49 additions & 23 deletions src/decompress.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,39 @@ constexpr auto distance_infos = std::array<LengthInfo, 30>{
{9, 1025}, {9, 1537}, {10, 2049}, {10, 3073}, {11, 4097},
{11, 6145}, {12, 8193}, {12, 12289}, {13, 16385}, {13, 24577}}};

enum class ParseLitOrLenStatus : std::uint8_t
{
EndOfBlock,
Error,
};

auto parse_lit_or_len(
std::uint16_t lit_or_len, huffman::bit_span& src_bits) -> std::
expected<std::variant<std::byte, std::uint16_t>, ParseLitOrLenStatus>
{
if (lit_or_len < detail::lit_or_len_end_of_block) {
return static_cast<std::byte>(lit_or_len);
}
if (lit_or_len == detail::lit_or_len_end_of_block) {
return std::unexpected{ParseLitOrLenStatus::EndOfBlock};
}
if (lit_or_len > detail::lit_or_len_max) {
return std::unexpected{ParseLitOrLenStatus::Error};
}
std::uint16_t len{};
if (lit_or_len == detail::lit_or_len_max) {
len = detail::lit_or_len_max_decoded;
} else {
const auto len_idx =
static_cast<size_t>(lit_or_len - detail::lit_or_len_end_of_block - 1);
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-constant-array-index)
const auto& len_info = detail::length_infos[len_idx];
const auto extra_len = src_bits.pop_n(len_info.extra_bits);
len = len_info.base + extra_len;
}
return len;
}

auto decompress_block_huffman(
huffman::bit_span& src_bits,
std::span<std::byte> dst,
Expand All @@ -81,36 +114,29 @@ auto decompress_block_huffman(
const huffman::table<std::uint16_t, fixed_dist_table_size>& dist_table)
-> DecompressStatus
{
std::uint16_t lit_or_len{};
while (true) {
const auto lit_or_len_decoded = huffman::decode_one(len_table, src_bits);
if (not lit_or_len_decoded.encoded_size) {
return DecompressStatus::InvalidLitOrLen;
}
lit_or_len = lit_or_len_decoded.symbol;
src_bits.consume(lit_or_len_decoded.encoded_size);
if (lit_or_len < detail::lit_or_len_end_of_block) {
dst[static_cast<std::size_t>(dst_written++)] =
static_cast<std::byte>(lit_or_len);
continue;
}
if (lit_or_len == detail::lit_or_len_end_of_block) {
break;
}
if (lit_or_len > detail::lit_or_len_max) {
const auto maybe_lit_or_len =
parse_lit_or_len(lit_or_len_decoded.symbol, src_bits);
if (not maybe_lit_or_len) {
if (maybe_lit_or_len.error() == ParseLitOrLenStatus::EndOfBlock) {
return DecompressStatus::Success;
}
return DecompressStatus::InvalidLitOrLen;
}
std::uint16_t len{};
if (lit_or_len == detail::lit_or_len_max) {
len = detail::lit_or_len_max_decoded;
} else {
const auto len_idx =
static_cast<size_t>(lit_or_len - detail::lit_or_len_end_of_block - 1);
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-constant-array-index)
const auto& len_info = detail::length_infos[len_idx];
const auto extra_len = src_bits.pop_n(len_info.extra_bits);
len = len_info.base + extra_len;
const auto lit_or_len = maybe_lit_or_len.value();
if (std::holds_alternative<std::byte>(lit_or_len)) {
if (dst.size() - static_cast<std::size_t>(dst_written) < 1) {
return DecompressStatus::DstTooSmall;
}
dst[static_cast<size_t>(dst_written++)] = std::get<std::byte>(lit_or_len);
continue;
}
const auto len = std::get<std::uint16_t>(lit_or_len);
const auto dist_decoded = huffman::decode_one(dist_table, src_bits);
const auto dist_code = dist_decoded.symbol;
if (not dist_decoded.encoded_size) {
Expand All @@ -131,15 +157,15 @@ auto decompress_block_huffman(
return DecompressStatus::DstTooSmall;
}
starflate::detail::copy_from_before(
dst.begin() + dst_written, distance, len);
distance, dst.begin() + dst_written, len);
dst_written += len;
}
return DecompressStatus::Success;
}

/// Copy n bytes from distance bytes before dst to dst.
void copy_from_before(
std::span<std::byte>::iterator dst, std::uint16_t distance, std::uint16_t n)
std::uint16_t distance, std::span<std::byte>::iterator dst, std::uint16_t n)
{
std::ptrdiff_t n_signed{n};
const auto src = dst - distance;
Expand Down
2 changes: 1 addition & 1 deletion src/decompress.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ constexpr auto lit_or_len_max_decoded = std::uint16_t{258};
///
/// @pre dst - distance is valid.
void copy_from_before(
std::span<std::byte>::iterator dst,
std::uint16_t distance,
std::span<std::byte>::iterator dst,
std::uint16_t n);
} // namespace detail

Expand Down
2 changes: 1 addition & 1 deletion src/test/decompress_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ auto main(int, char* argv[]) -> int
test("copy_from_before") = [] {
auto src_and_dst = huffman::byte_array(1, 2, 0, 0, 0, 0);
const auto dst_span = std::span<std::byte>{src_and_dst}.subspan(2);
detail::copy_from_before(dst_span.begin(), 2, 3);
detail::copy_from_before(2, dst_span.begin(), 3);
expect(eq(src_and_dst, huffman::byte_array(1, 2, 1, 2, 1, 0)));
};
};

0 comments on commit f5faa04

Please sign in to comment.