From 54e6d357cbc2fc2f29bc0a40c9adb4d131df557a Mon Sep 17 00:00:00 2001 From: Gary Miguel Date: Wed, 28 Jun 2023 21:32:38 -0700 Subject: [PATCH] WIP huffman decode Change-Id: I97309a7fd3c7059fe439fe516ba97920b53b5fcd --- huffman/BUILD.bazel | 1 + huffman/huffman.hpp | 1 + huffman/src/code.hpp | 15 ++++++++++++ huffman/src/decode.hpp | 46 ++++++++++++++++++++++++++++++++++++ huffman/test/BUILD.bazel | 10 ++++++++ huffman/test/decode_test.cpp | 42 ++++++++++++++++++++++++++++++++ 6 files changed, 115 insertions(+) create mode 100644 huffman/src/decode.hpp create mode 100644 huffman/test/decode_test.cpp diff --git a/huffman/BUILD.bazel b/huffman/BUILD.bazel index a0391cb..9e31fb5 100644 --- a/huffman/BUILD.bazel +++ b/huffman/BUILD.bazel @@ -6,6 +6,7 @@ cc_library( "src/bit.hpp", "src/bit_span.hpp", "src/code.hpp", + "src/decode.hpp", "src/detail/base_view.hpp", "src/detail/iterator_interface.hpp", "src/detail/static_vector.hpp", diff --git a/huffman/huffman.hpp b/huffman/huffman.hpp index 986be4b..649cf07 100644 --- a/huffman/huffman.hpp +++ b/huffman/huffman.hpp @@ -3,5 +3,6 @@ #include "huffman/src/bit.hpp" #include "huffman/src/bit_span.hpp" #include "huffman/src/code.hpp" +#include "huffman/src/decode.hpp" #include "huffman/src/encoding.hpp" #include "huffman/src/table.hpp" diff --git a/huffman/src/code.hpp b/huffman/src/code.hpp index faafd93..08aea71 100644 --- a/huffman/src/code.hpp +++ b/huffman/src/code.hpp @@ -86,6 +86,21 @@ class code return std::move(c); } + /// Right pad `c` with `b` + /// + friend constexpr auto operator<<(code& c, bit b) -> code& + { + c.value_ <<= 1U; + c.value_ |= static_cast(bool(b)); + ++c.bitsize_; + return c; + } + friend constexpr auto operator<<(code&& c, bit b) -> code&& + { + c << b; + return std::move(c); + } + /// Inserts a textual representation of `c` into `os` /// friend auto operator<<(std::ostream& os, const code& c) -> std::ostream& diff --git a/huffman/src/decode.hpp b/huffman/src/decode.hpp new file mode 100644 index 0000000..ec33601 --- /dev/null +++ b/huffman/src/decode.hpp @@ -0,0 +1,46 @@ +#pragma once +#include "huffman/src/bit_span.hpp" +#include "huffman/src/code.hpp" +#include "huffman/src/table.hpp" + +namespace gpu_deflate::huffman { +/// Decodes a bit stream using a code table. +/// +/// If a code from \p bits is not found in \p code_table, the +/// decoding is aborted. +/// +/// @param code_table The code table to use for decoding. +/// @param bits The bit stream to decode. +/// @param output The output iterator to write the decoded symbols to. +/// +/// @returns The output iterator after writing the decoded symbols. +/// @tparam Symbol The type of the symbols in the code table. +/// @tparam Extent The extent of the code table. +/// @tparam O The type of the output iterator. +template < + std::regular Symbol, + std::size_t Extent = std::dynamic_extent, + class O> +auto decode(const table& code_table, bit_span bits, O output) + -> O +{ + code current_code{}; + auto code_table_pos = code_table.begin(); + for (auto bit : bits) { + current_code << bit; + auto found = code_table.find(current_code, code_table_pos); + if (found) { + *output = found->symbol; + output++; + code_table_pos = code_table.begin(); + current_code = code{}; + continue; + } + if (found.error() == code_table.end()) { + break; + } + code_table_pos = found.error(); + } + return output; +} +} // namespace gpu_deflate::huffman diff --git a/huffman/test/BUILD.bazel b/huffman/test/BUILD.bazel index cee9e2a..9e61c9b 100644 --- a/huffman/test/BUILD.bazel +++ b/huffman/test/BUILD.bazel @@ -70,6 +70,16 @@ cc_test( ], ) +cc_test( + name = "decode_test", + timeout = "short", + srcs = ["decode_test.cpp"], + deps = [ + "//huffman", + "@boost_ut", + ], +) + cc_binary( name = "bench", srcs = ["bench.cpp"], diff --git a/huffman/test/decode_test.cpp b/huffman/test/decode_test.cpp new file mode 100644 index 0000000..3ed3df1 --- /dev/null +++ b/huffman/test/decode_test.cpp @@ -0,0 +1,42 @@ +#include "huffman/huffman.hpp" + +#include + +#include +#include +#include +#include + +auto main() -> int +{ + using ::boost::ut::expect; + using ::boost::ut::test; + + namespace huffman = ::gpu_deflate::huffman; + + test("basic") = [] { + // encoded data from dahuffman readme.rst, but in hex. + constexpr std::array bytes = { + std::byte{0x86}, + std::byte{0x7c}, + std::byte{0x25}, + std::byte{0x13}, + std::byte{0x69}, + std::byte{0x40}}; + + constexpr auto code_table = // clang-format off + huffman::table{ + huffman::table_contents, + {std::pair{00000_c, '\4'}, + {00001_c, 'x'}, + {0001_c, 'q'}, + {001_c, 'n'}, + {01_c, 'i'}, + {1_c, 'e'}} + }; // clang-format on + + constexpr std::vector output_buf; + const auto result = + decode(bytes, code_table, std::back_inserter(output_buf)); + }; +}