Skip to content

Commit

Permalink
construct huffman table directly on reversed elements
Browse files Browse the repository at this point in the history
Change-Id: Ic42b6b1c03f10077d19d49a9e6544214834ba42f
  • Loading branch information
oliverlee committed Sep 28, 2023
1 parent bc94c5c commit 5bb362f
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 25 deletions.
32 changes: 19 additions & 13 deletions huffman/src/detail/table_node.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,30 +114,36 @@ class table_node : public encoding<Symbol>
return init_.node_size;
}
/// "Joins" two `table_node`s
/// @param lhs left table_node
/// @param rhs right table_node
/// @pre `&lhs + lhs.node_size() == &rhs`
/// @param lhs left table_node
/// @pre `&rhs - rhs.node_size() == &lhs`
///
/// Logically "join" `rhs` with the next adjacent node `lhs` "creating" an
/// internal node. This adds the frequency of `lhs` to `rhs`, left pads all
/// the codes of the internal nodes of `rhs` with 0s and left pads all the
/// code of the internal nodes of `lhs` with 1s.
///
/// Logically "join" `lhs` with the next adjacent node `rhs` "creating" an
/// internal node. This adds the frequency of `rhs` to `lhs`, left pads all
/// the codes of the internal nodes of `lhs` with 0s and left pads all the
/// code of the internal nodes of `rhs` with 1s.
/// @attention This is intended to be used with a reversed view of table
/// elements.
///
friend constexpr auto join(table_node& lhs, table_node& rhs) -> void
friend constexpr auto join_reversed(table_node& rhs, table_node& lhs) -> void
{
assert(
&lhs + lhs.node_size() == &rhs and "`lhs` and `rhs` are not adjacent");
assert(&rhs == &lhs + rhs.node_size() and //
"`rhs` and `lhs` are not adjacent");

const auto left_pad_with = [](auto b) {
return [b](table_node& n) { b >> static_cast<code&>(n); };
};

std::for_each(&lhs, &rhs, left_pad_with(bit{0}));
std::for_each(&rhs, &rhs + rhs.node_size(), left_pad_with(bit{1}));
std::for_each(&lhs + 1, &rhs + 1, left_pad_with(bit{0}));
std::for_each(
&lhs + (1 - static_cast<std::ptrdiff_t>(lhs.node_size())),
&lhs + 1,
left_pad_with(bit{1}));

// NOLINTBEGIN(cppcoreguidelines-pro-type-union-access)
lhs.init_.frequency += rhs.frequency();
lhs.init_.node_size += rhs.node_size();
rhs.init_.frequency += lhs.frequency();
rhs.init_.node_size += lhs.node_size();
// NOLINTEND(cppcoreguidelines-pro-type-union-access)
}

Expand Down
27 changes: 15 additions & 12 deletions huffman/src/table.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,18 +69,20 @@ class table

constexpr auto encode_symbols() -> void
{
auto reversed = std::views::reverse(table_);

// precondition, audit
assert(std::ranges::is_sorted(table_));
assert(std::ranges::is_sorted(reversed));

const auto total_size = table_.size();
auto first = table_.begin();
const auto last = table_.end();
const auto total_size = reversed.size();
auto first = reversed.begin();
const auto last = reversed.end();

while (first->node_size() != total_size) {
join(first[0], first[to_index(first->node_size())]);
join_reversed(first[0], first[to_index(first->node_size())]);

const auto has_higher_freq = [f = first->frequency()](const auto& n) {
return n.frequency() > f;
const auto has_higher_freq = [&first](const auto& n) {
return n.frequency() > first->frequency();
};

auto lower = first + to_index(first->node_size());
Expand All @@ -105,25 +107,26 @@ class table
return;
}

std::ranges::sort(table_);
auto reversed = std::views::reverse(table_);

std::ranges::sort(reversed);

// precondition
assert(
std::ranges::unique(
table_, {}, [](const auto& elem) { return elem.symbol; })
reversed, {}, [](const auto& elem) { return elem.symbol; })
.empty() and
"a `table` cannot contain duplicate symbols");

const auto frequencies = std::views::transform(
table_, [](const auto& elem) { return elem.frequency(); });
reversed, [](const auto& elem) { return elem.frequency(); });
[[maybe_unused]] const auto total_freq =
std::accumulate(std::cbegin(frequencies), std::cend(frequencies), 0UZ);

encode_symbols();

// postcondition
assert(total_freq == table_.front().frequency());
std::ranges::reverse(table_);
assert(total_freq == reversed.front().frequency());
}

constexpr auto set_skip_fields() -> void
Expand Down

0 comments on commit 5bb362f

Please sign in to comment.