Skip to content

Commit

Permalink
AK+LibCompress: Allow peeking more bits than available
Browse files Browse the repository at this point in the history
...and then fail only when discard_previously_peeked_bits() more
bits than we have.

`unzip ~/Downloads/enwik8.zip`: 1.005s -> 1.050s
4.9% slowdown :/

Fixes SerenityOS#25005
  • Loading branch information
nico committed Sep 9, 2024
1 parent 26d7301 commit 172ede6
Show file tree
Hide file tree
Showing 2 changed files with 8 additions and 12 deletions.
18 changes: 7 additions & 11 deletions AK/BitStream.h
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ class LittleEndianInputBitStream : public LittleEndianBitStream {
ErrorOr<T> read_bits(size_t count)
{
auto result = TRY(peek_bits<T>(count));
discard_previously_peeked_bits(count);
TRY(discard_previously_peeked_bits(count));

return result;
}
Expand All @@ -222,15 +222,14 @@ class LittleEndianInputBitStream : public LittleEndianBitStream {
return m_bit_buffer & lsb_mask<T>(min(count, m_bit_count));
}

ALWAYS_INLINE void discard_previously_peeked_bits(u8 count)
ALWAYS_INLINE ErrorOr<void> discard_previously_peeked_bits(u8 count)
{
// We allow "retrieving" more bits than we can provide, but we need to make sure that we don't underflow the current bit counter.
// This only affects certain "modes", but all the relevant checks have been handled in the respective `peek_bits` call.
if (count > m_bit_count)
count = m_bit_count;
return Error::from_string_literal("Reached end-of-stream without collecting the required number of bits");

m_bit_buffer >>= count;
m_bit_count -= count;
return {};
}

/// Discards any sub-byte stream positioning the input stream may be keeping track of.
Expand All @@ -241,7 +240,7 @@ class LittleEndianInputBitStream : public LittleEndianBitStream {

if (auto offset = m_bit_count % bits_per_byte; offset != 0) {
remaining_bits = m_bit_buffer & lsb_mask<u8>(offset);
discard_previously_peeked_bits(offset);
MUST(discard_previously_peeked_bits(offset));
}

return remaining_bits;
Expand All @@ -252,12 +251,9 @@ class LittleEndianInputBitStream : public LittleEndianBitStream {
{
while (requested_bit_count > m_bit_count) [[likely]] {
if (m_stream->is_eof()) [[unlikely]] {
if (m_unsatisfiable_read_behavior == UnsatisfiableReadBehavior::FillWithZero) {
if (m_unsatisfiable_read_behavior == UnsatisfiableReadBehavior::FillWithZero)
m_bit_count = requested_bit_count;
return {};
}

return Error::from_string_literal("Reached end-of-stream without collecting the required number of bits");
return {};
}

size_t bits_to_read = bit_buffer_size - m_bit_count;
Expand Down
2 changes: 1 addition & 1 deletion Userland/Libraries/LibCompress/Deflate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ ErrorOr<u32> CanonicalCode::read_symbol(LittleEndianInputBitStream& stream) cons
auto prefix = TRY(stream.peek_bits<size_t>(m_max_prefixed_code_length));

if (auto [symbol_value, code_length] = m_prefix_table[prefix]; code_length != 0) {
stream.discard_previously_peeked_bits(code_length);
TRY(stream.discard_previously_peeked_bits(code_length));
return symbol_value;
}

Expand Down

0 comments on commit 172ede6

Please sign in to comment.