Coverage Report

Created: 2025-12-18 07:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/serenity/AK/BitStream.h
Line
Count
Source
1
/*
2
 * Copyright (c) 2021, kleines Filmröllchen <filmroellchen@serenityos.org>.
3
 *
4
 * SPDX-License-Identifier: BSD-2-Clause
5
 */
6
7
#pragma once
8
9
#include <AK/ByteBuffer.h>
10
#include <AK/Concepts.h>
11
#include <AK/MaybeOwned.h>
12
#include <AK/NumericLimits.h>
13
#include <AK/OwnPtr.h>
14
#include <AK/Stream.h>
15
16
namespace AK {
17
18
/// A stream wrapper class that allows you to read arbitrary amounts of bits
19
/// in big-endian order from another stream.
20
class BigEndianInputBitStream : public Stream {
21
public:
22
    explicit BigEndianInputBitStream(MaybeOwned<Stream> stream)
23
1.61M
        : m_stream(move(stream))
24
1.61M
    {
25
1.61M
    }
26
27
    // ^Stream
28
    virtual ErrorOr<Bytes> read_some(Bytes bytes) override
29
168k
    {
30
168k
        if (m_current_byte.has_value() && is_aligned_to_byte_boundary()) {
31
0
            bytes[0] = m_current_byte.release_value();
32
0
            auto freshly_read_bytes = TRY(m_stream->read_some(bytes.slice(1)));
33
0
            return bytes.trim(1 + freshly_read_bytes.size());
34
0
        }
35
168k
        align_to_byte_boundary();
36
168k
        return m_stream->read_some(bytes);
37
168k
    }
38
0
    virtual ErrorOr<size_t> write_some(ReadonlyBytes bytes) override { return m_stream->write_some(bytes); }
39
508k
    virtual bool is_eof() const override { return m_stream->is_eof() && !m_current_byte.has_value(); }
40
0
    virtual bool is_open() const override { return m_stream->is_open(); }
41
    virtual void close() override
42
0
    {
43
0
        m_stream->close();
44
0
        align_to_byte_boundary();
45
0
    }
46
47
    ErrorOr<bool> read_bit()
48
33.5M
    {
49
33.5M
        return read_bits<bool>(1);
50
33.5M
    }
51
52
    /// Depending on the number of bits to read, the return type can be chosen appropriately.
53
    /// This avoids a bunch of static_cast<>'s for the user.
54
    // TODO: Support u128, u256 etc. as well: The concepts would be quite complex.
55
    template<Unsigned T = u64>
56
    ErrorOr<T> read_bits(size_t count)
57
425M
    {
58
425M
        if constexpr (IsSame<bool, T>) {
59
33.5M
            VERIFY(count == 1);
60
33.5M
        }
61
33.5M
        T result = 0;
62
63
425M
        size_t nread = 0;
64
1.33G
        while (nread < count) {
65
908M
            if (m_current_byte.has_value()) {
66
682M
                if constexpr (!IsSame<bool, T> && !IsSame<u8, T>) {
67
                    // read as many bytes as possible directly
68
645M
                    if (((count - nread) >= 8) && is_aligned_to_byte_boundary()) {
69
                        // shift existing data over
70
160M
                        result <<= 8;
71
160M
                        result |= m_current_byte.value();
72
160M
                        nread += 8;
73
160M
                        m_current_byte.clear();
74
484M
                    } else {
75
484M
                        auto const bit = (m_current_byte.value() >> (7 - m_bit_offset)) & 1;
76
484M
                        result <<= 1;
77
484M
                        result |= bit;
78
484M
                        ++nread;
79
484M
                        if (m_bit_offset++ == 7)
80
58.4M
                            m_current_byte.clear();
81
484M
                    }
82
645M
                } else {
83
                    // Always take this branch for booleans or u8: there's no purpose in reading more than a single bit
84
37.6M
                    auto const bit = (m_current_byte.value() >> (7 - m_bit_offset)) & 1;
85
                    if constexpr (IsSame<bool, T>)
86
33.5M
                        result = bit;
87
4.08M
                    else {
88
4.08M
                        result <<= 1;
89
4.08M
                        result |= bit;
90
4.08M
                    }
91
37.6M
                    ++nread;
92
37.6M
                    if (m_bit_offset++ == 7)
93
5.99M
                        m_current_byte.clear();
94
37.6M
                }
95
682M
            } else {
96
226M
                m_current_byte = TRY(m_stream->read_value<u8>());
97
226M
                m_bit_offset = 0;
98
226M
            }
99
908M
        }
100
101
425M
        return result;
102
425M
    }
_ZN2AK23BigEndianInputBitStream9read_bitsITkNS_8Concepts8UnsignedEbEENS_7ErrorOrIT_NS_5ErrorEEEm
Line
Count
Source
57
33.5M
    {
58
33.5M
        if constexpr (IsSame<bool, T>) {
59
33.5M
            VERIFY(count == 1);
60
33.5M
        }
61
33.5M
        T result = 0;
62
63
33.5M
        size_t nread = 0;
64
70.9M
        while (nread < count) {
65
37.3M
            if (m_current_byte.has_value()) {
66
                if constexpr (!IsSame<bool, T> && !IsSame<u8, T>) {
67
                    // read as many bytes as possible directly
68
                    if (((count - nread) >= 8) && is_aligned_to_byte_boundary()) {
69
                        // shift existing data over
70
                        result <<= 8;
71
                        result |= m_current_byte.value();
72
                        nread += 8;
73
                        m_current_byte.clear();
74
                    } else {
75
                        auto const bit = (m_current_byte.value() >> (7 - m_bit_offset)) & 1;
76
                        result <<= 1;
77
                        result |= bit;
78
                        ++nread;
79
                        if (m_bit_offset++ == 7)
80
                            m_current_byte.clear();
81
                    }
82
33.5M
                } else {
83
                    // Always take this branch for booleans or u8: there's no purpose in reading more than a single bit
84
33.5M
                    auto const bit = (m_current_byte.value() >> (7 - m_bit_offset)) & 1;
85
                    if constexpr (IsSame<bool, T>)
86
33.5M
                        result = bit;
87
                    else {
88
                        result <<= 1;
89
                        result |= bit;
90
                    }
91
33.5M
                    ++nread;
92
33.5M
                    if (m_bit_offset++ == 7)
93
5.66M
                        m_current_byte.clear();
94
33.5M
                }
95
33.5M
            } else {
96
3.79M
                m_current_byte = TRY(m_stream->read_value<u8>());
97
3.79M
                m_bit_offset = 0;
98
3.79M
            }
99
37.3M
        }
100
101
33.5M
        return result;
102
33.5M
    }
_ZN2AK23BigEndianInputBitStream9read_bitsITkNS_8Concepts8UnsignedEmEENS_7ErrorOrIT_NS_5ErrorEEEm
Line
Count
Source
57
37.5M
    {
58
        if constexpr (IsSame<bool, T>) {
59
            VERIFY(count == 1);
60
        }
61
37.5M
        T result = 0;
62
63
37.5M
        size_t nread = 0;
64
123M
        while (nread < count) {
65
85.5M
            if (m_current_byte.has_value()) {
66
61.7M
                if constexpr (!IsSame<bool, T> && !IsSame<u8, T>) {
67
                    // read as many bytes as possible directly
68
61.7M
                    if (((count - nread) >= 8) && is_aligned_to_byte_boundary()) {
69
                        // shift existing data over
70
17.2M
                        result <<= 8;
71
17.2M
                        result |= m_current_byte.value();
72
17.2M
                        nread += 8;
73
17.2M
                        m_current_byte.clear();
74
44.5M
                    } else {
75
44.5M
                        auto const bit = (m_current_byte.value() >> (7 - m_bit_offset)) & 1;
76
44.5M
                        result <<= 1;
77
44.5M
                        result |= bit;
78
44.5M
                        ++nread;
79
44.5M
                        if (m_bit_offset++ == 7)
80
3.59M
                            m_current_byte.clear();
81
44.5M
                    }
82
                } else {
83
                    // Always take this branch for booleans or u8: there's no purpose in reading more than a single bit
84
                    auto const bit = (m_current_byte.value() >> (7 - m_bit_offset)) & 1;
85
                    if constexpr (IsSame<bool, T>)
86
                        result = bit;
87
                    else {
88
                        result <<= 1;
89
                        result |= bit;
90
                    }
91
                    ++nread;
92
                    if (m_bit_offset++ == 7)
93
                        m_current_byte.clear();
94
                }
95
61.7M
            } else {
96
23.7M
                m_current_byte = TRY(m_stream->read_value<u8>());
97
23.7M
                m_bit_offset = 0;
98
23.7M
            }
99
85.5M
        }
100
101
37.5M
        return result;
102
37.5M
    }
_ZN2AK23BigEndianInputBitStream9read_bitsITkNS_8Concepts8UnsignedEhEENS_7ErrorOrIT_NS_5ErrorEEEm
Line
Count
Source
57
815k
    {
58
        if constexpr (IsSame<bool, T>) {
59
            VERIFY(count == 1);
60
        }
61
815k
        T result = 0;
62
63
815k
        size_t nread = 0;
64
5.27M
        while (nread < count) {
65
4.46M
            if (m_current_byte.has_value()) {
66
                if constexpr (!IsSame<bool, T> && !IsSame<u8, T>) {
67
                    // read as many bytes as possible directly
68
                    if (((count - nread) >= 8) && is_aligned_to_byte_boundary()) {
69
                        // shift existing data over
70
                        result <<= 8;
71
                        result |= m_current_byte.value();
72
                        nread += 8;
73
                        m_current_byte.clear();
74
                    } else {
75
                        auto const bit = (m_current_byte.value() >> (7 - m_bit_offset)) & 1;
76
                        result <<= 1;
77
                        result |= bit;
78
                        ++nread;
79
                        if (m_bit_offset++ == 7)
80
                            m_current_byte.clear();
81
                    }
82
4.08M
                } else {
83
                    // Always take this branch for booleans or u8: there's no purpose in reading more than a single bit
84
4.08M
                    auto const bit = (m_current_byte.value() >> (7 - m_bit_offset)) & 1;
85
                    if constexpr (IsSame<bool, T>)
86
                        result = bit;
87
4.08M
                    else {
88
4.08M
                        result <<= 1;
89
4.08M
                        result |= bit;
90
4.08M
                    }
91
4.08M
                    ++nread;
92
4.08M
                    if (m_bit_offset++ == 7)
93
334k
                        m_current_byte.clear();
94
4.08M
                }
95
4.08M
            } else {
96
379k
                m_current_byte = TRY(m_stream->read_value<u8>());
97
379k
                m_bit_offset = 0;
98
379k
            }
99
4.46M
        }
100
101
815k
        return result;
102
815k
    }
_ZN2AK23BigEndianInputBitStream9read_bitsITkNS_8Concepts8UnsignedEtEENS_7ErrorOrIT_NS_5ErrorEEEm
Line
Count
Source
57
2.06M
    {
58
        if constexpr (IsSame<bool, T>) {
59
            VERIFY(count == 1);
60
        }
61
2.06M
        T result = 0;
62
63
2.06M
        size_t nread = 0;
64
9.47M
        while (nread < count) {
65
7.40M
            if (m_current_byte.has_value()) {
66
4.90M
                if constexpr (!IsSame<bool, T> && !IsSame<u8, T>) {
67
                    // read as many bytes as possible directly
68
4.90M
                    if (((count - nread) >= 8) && is_aligned_to_byte_boundary()) {
69
                        // shift existing data over
70
2.12M
                        result <<= 8;
71
2.12M
                        result |= m_current_byte.value();
72
2.12M
                        nread += 8;
73
2.12M
                        m_current_byte.clear();
74
2.77M
                    } else {
75
2.77M
                        auto const bit = (m_current_byte.value() >> (7 - m_bit_offset)) & 1;
76
2.77M
                        result <<= 1;
77
2.77M
                        result |= bit;
78
2.77M
                        ++nread;
79
2.77M
                        if (m_bit_offset++ == 7)
80
258k
                            m_current_byte.clear();
81
2.77M
                    }
82
                } else {
83
                    // Always take this branch for booleans or u8: there's no purpose in reading more than a single bit
84
                    auto const bit = (m_current_byte.value() >> (7 - m_bit_offset)) & 1;
85
                    if constexpr (IsSame<bool, T>)
86
                        result = bit;
87
                    else {
88
                        result <<= 1;
89
                        result |= bit;
90
                    }
91
                    ++nread;
92
                    if (m_bit_offset++ == 7)
93
                        m_current_byte.clear();
94
                }
95
4.90M
            } else {
96
2.50M
                m_current_byte = TRY(m_stream->read_value<u8>());
97
2.50M
                m_bit_offset = 0;
98
2.50M
            }
99
7.40M
        }
100
101
2.06M
        return result;
102
2.06M
    }
_ZN2AK23BigEndianInputBitStream9read_bitsITkNS_8Concepts8UnsignedEjEENS_7ErrorOrIT_NS_5ErrorEEEm
Line
Count
Source
57
351M
    {
58
        if constexpr (IsSame<bool, T>) {
59
            VERIFY(count == 1);
60
        }
61
351M
        T result = 0;
62
63
351M
        size_t nread = 0;
64
1.12G
        while (nread < count) {
65
774M
            if (m_current_byte.has_value()) {
66
578M
                if constexpr (!IsSame<bool, T> && !IsSame<u8, T>) {
67
                    // read as many bytes as possible directly
68
578M
                    if (((count - nread) >= 8) && is_aligned_to_byte_boundary()) {
69
                        // shift existing data over
70
141M
                        result <<= 8;
71
141M
                        result |= m_current_byte.value();
72
141M
                        nread += 8;
73
141M
                        m_current_byte.clear();
74
437M
                    } else {
75
437M
                        auto const bit = (m_current_byte.value() >> (7 - m_bit_offset)) & 1;
76
437M
                        result <<= 1;
77
437M
                        result |= bit;
78
437M
                        ++nread;
79
437M
                        if (m_bit_offset++ == 7)
80
54.6M
                            m_current_byte.clear();
81
437M
                    }
82
                } else {
83
                    // Always take this branch for booleans or u8: there's no purpose in reading more than a single bit
84
                    auto const bit = (m_current_byte.value() >> (7 - m_bit_offset)) & 1;
85
                    if constexpr (IsSame<bool, T>)
86
                        result = bit;
87
                    else {
88
                        result <<= 1;
89
                        result |= bit;
90
                    }
91
                    ++nread;
92
                    if (m_bit_offset++ == 7)
93
                        m_current_byte.clear();
94
                }
95
578M
            } else {
96
195M
                m_current_byte = TRY(m_stream->read_value<u8>());
97
195M
                m_bit_offset = 0;
98
195M
            }
99
774M
        }
100
101
351M
        return result;
102
351M
    }
Unexecuted instantiation: _ZN2AK23BigEndianInputBitStream9read_bitsITkNS_8Concepts8UnsignedEbEENS_7ErrorOrIT_NS_5ErrorEEEm
103
104
    /// Discards any sub-byte stream positioning the input stream may be keeping track of.
105
    /// Non-bitwise reads will implicitly call this.
106
    void align_to_byte_boundary()
107
936k
    {
108
936k
        m_current_byte.clear();
109
936k
        m_bit_offset = 0;
110
936k
    }
111
112
    /// Whether we are (accidentally or intentionally) at a byte boundary right now.
113
242M
    ALWAYS_INLINE bool is_aligned_to_byte_boundary() const { return m_bit_offset % 8 == 0; }
114
19
    ALWAYS_INLINE u8 bits_until_next_byte_boundary() const { return m_bit_offset % 8 == 0 ? 0 : 8 - m_bit_offset; }
115
116
private:
117
    Optional<u8> m_current_byte;
118
    size_t m_bit_offset { 0 };
119
    MaybeOwned<Stream> m_stream;
120
};
121
122
class LittleEndianBitStream : public Stream {
123
protected:
124
    using BufferType = u64;
125
126
    static constexpr size_t bits_per_byte = 8u;
127
    static constexpr size_t bit_buffer_size = sizeof(BufferType) * bits_per_byte;
128
129
    explicit LittleEndianBitStream(MaybeOwned<Stream> stream)
130
342k
        : m_stream(move(stream))
131
342k
    {
132
342k
    }
133
134
    template<Unsigned T>
135
    static constexpr T lsb_mask(T bits)
136
1.02G
    {
137
1.02G
        constexpr auto max = NumericLimits<T>::max();
138
1.02G
        constexpr auto digits = NumericLimits<T>::digits();
139
140
1.02G
        return bits == 0 ? 0 : max >> (digits - bits);
141
1.02G
    }
_ZN2AK21LittleEndianBitStream8lsb_maskITkNS_8Concepts8UnsignedEhEET_S3_
Line
Count
Source
136
115k
    {
137
115k
        constexpr auto max = NumericLimits<T>::max();
138
115k
        constexpr auto digits = NumericLimits<T>::digits();
139
140
115k
        return bits == 0 ? 0 : max >> (digits - bits);
141
115k
    }
_ZN2AK21LittleEndianBitStream8lsb_maskITkNS_8Concepts8UnsignedEmEET_S3_
Line
Count
Source
136
911M
    {
137
911M
        constexpr auto max = NumericLimits<T>::max();
138
911M
        constexpr auto digits = NumericLimits<T>::digits();
139
140
911M
        return bits == 0 ? 0 : max >> (digits - bits);
141
911M
    }
_ZN2AK21LittleEndianBitStream8lsb_maskITkNS_8Concepts8UnsignedEbEET_S3_
Line
Count
Source
136
97.4M
    {
137
97.4M
        constexpr auto max = NumericLimits<T>::max();
138
97.4M
        constexpr auto digits = NumericLimits<T>::digits();
139
140
97.4M
        return bits == 0 ? 0 : max >> (digits - bits);
141
97.4M
    }
_ZN2AK21LittleEndianBitStream8lsb_maskITkNS_8Concepts8UnsignedEtEET_S3_
Line
Count
Source
136
20.1M
    {
137
20.1M
        constexpr auto max = NumericLimits<T>::max();
138
20.1M
        constexpr auto digits = NumericLimits<T>::digits();
139
140
20.1M
        return bits == 0 ? 0 : max >> (digits - bits);
141
20.1M
    }
142
143
12.4k
    ALWAYS_INLINE bool is_aligned_to_byte_boundary() const { return m_bit_count % bits_per_byte == 0; }
144
145
    MaybeOwned<Stream> m_stream;
146
147
    BufferType m_bit_buffer { 0 };
148
    u8 m_bit_count { 0 };
149
};
150
151
/// A stream wrapper class that allows you to read arbitrary amounts of bits
152
/// in little-endian order from another stream.
153
class LittleEndianInputBitStream : public LittleEndianBitStream {
154
public:
155
    enum UnsatisfiableReadBehavior {
156
        Reject,
157
        FillWithZero,
158
    };
159
160
    explicit LittleEndianInputBitStream(MaybeOwned<Stream> stream, UnsatisfiableReadBehavior unsatisfiable_read_behavior = UnsatisfiableReadBehavior::Reject)
161
339k
        : LittleEndianBitStream(move(stream))
162
339k
        , m_unsatisfiable_read_behavior(unsatisfiable_read_behavior)
163
339k
    {
164
339k
    }
165
166
    // ^Stream
167
    virtual ErrorOr<Bytes> read_some(Bytes bytes) override
168
5.42M
    {
169
5.42M
        align_to_byte_boundary();
170
171
5.42M
        size_t bytes_read = 0;
172
5.42M
        auto buffer = bytes;
173
174
5.42M
        if (m_bit_count > 0) {
175
138k
            auto bits_to_read = min(buffer.size() * bits_per_byte, m_bit_count);
176
138k
            auto result = TRY(read_bits(bits_to_read));
177
178
138k
            bytes_read = bits_to_read / bits_per_byte;
179
138k
            buffer.overwrite(0, &result, bytes_read);
180
181
138k
            buffer = buffer.slice(bytes_read);
182
138k
        }
183
184
5.42M
        buffer = TRY(m_stream->read_some(buffer));
185
5.42M
        bytes_read += buffer.size();
186
187
5.42M
        return bytes.trim(bytes_read);
188
5.42M
    }
AK::LittleEndianInputBitStream::read_some(AK::Span<unsigned char>)
Line
Count
Source
168
5.42M
    {
169
5.42M
        align_to_byte_boundary();
170
171
5.42M
        size_t bytes_read = 0;
172
5.42M
        auto buffer = bytes;
173
174
5.42M
        if (m_bit_count > 0) {
175
138k
            auto bits_to_read = min(buffer.size() * bits_per_byte, m_bit_count);
176
138k
            auto result = TRY(read_bits(bits_to_read));
177
178
138k
            bytes_read = bits_to_read / bits_per_byte;
179
138k
            buffer.overwrite(0, &result, bytes_read);
180
181
138k
            buffer = buffer.slice(bytes_read);
182
138k
        }
183
184
5.42M
        buffer = TRY(m_stream->read_some(buffer));
185
5.42M
        bytes_read += buffer.size();
186
187
5.42M
        return bytes.trim(bytes_read);
188
5.42M
    }
Unexecuted instantiation: AK::LittleEndianInputBitStream::read_some(AK::Span<unsigned char>)
189
190
0
    virtual ErrorOr<size_t> write_some(ReadonlyBytes bytes) override { return m_stream->write_some(bytes); }
191
9.38M
    virtual bool is_eof() const override { return m_stream->is_eof() && m_bit_count == 0; }
192
0
    virtual bool is_open() const override { return m_stream->is_open(); }
193
    virtual void close() override
194
0
    {
195
0
        m_stream->close();
196
0
        align_to_byte_boundary();
197
0
    }
198
199
    ErrorOr<bool> read_bit()
200
97.4M
    {
201
97.4M
        return read_bits<bool>(1);
202
97.4M
    }
203
204
    /// Depending on the number of bits to read, the return type can be chosen appropriately.
205
    /// This avoids a bunch of static_cast<>'s for the user.
206
    // TODO: Support u128, u256 etc. as well: The concepts would be quite complex.
207
    template<Unsigned T = u64>
208
    ErrorOr<T> read_bits(size_t count)
209
366M
    {
210
366M
        auto result = TRY(peek_bits<T>(count));
211
366M
        discard_previously_peeked_bits(count);
212
213
366M
        return result;
214
366M
    }
_ZN2AK26LittleEndianInputBitStream9read_bitsITkNS_8Concepts8UnsignedEmEENS_7ErrorOrIT_NS_5ErrorEEEm
Line
Count
Source
209
248M
    {
210
248M
        auto result = TRY(peek_bits<T>(count));
211
248M
        discard_previously_peeked_bits(count);
212
213
248M
        return result;
214
248M
    }
_ZN2AK26LittleEndianInputBitStream9read_bitsITkNS_8Concepts8UnsignedEbEENS_7ErrorOrIT_NS_5ErrorEEEm
Line
Count
Source
209
97.4M
    {
210
97.4M
        auto result = TRY(peek_bits<T>(count));
211
97.4M
        discard_previously_peeked_bits(count);
212
213
97.4M
        return result;
214
97.4M
    }
_ZN2AK26LittleEndianInputBitStream9read_bitsITkNS_8Concepts8UnsignedEtEENS_7ErrorOrIT_NS_5ErrorEEEm
Line
Count
Source
209
20.1M
    {
210
20.1M
        auto result = TRY(peek_bits<T>(count));
211
20.1M
        discard_previously_peeked_bits(count);
212
213
20.1M
        return result;
214
20.1M
    }
Unexecuted instantiation: _ZN2AK26LittleEndianInputBitStream9read_bitsITkNS_8Concepts8UnsignedEhEENS_7ErrorOrIT_NS_5ErrorEEEm
215
216
    template<Unsigned T = u64>
217
    ErrorOr<T> peek_bits(size_t count)
218
1.01G
    {
219
1.01G
        if (count > m_bit_count)
220
470M
            TRY(refill_buffer_from_stream(count));
221
222
1.01G
        return m_bit_buffer & lsb_mask<T>(min(count, m_bit_count));
223
1.01G
    }
_ZN2AK26LittleEndianInputBitStream9peek_bitsITkNS_8Concepts8UnsignedEmEENS_7ErrorOrIT_NS_5ErrorEEEm
Line
Count
Source
218
901M
    {
219
901M
        if (count > m_bit_count)
220
466M
            TRY(refill_buffer_from_stream(count));
221
222
901M
        return m_bit_buffer & lsb_mask<T>(min(count, m_bit_count));
223
901M
    }
_ZN2AK26LittleEndianInputBitStream9peek_bitsITkNS_8Concepts8UnsignedEbEENS_7ErrorOrIT_NS_5ErrorEEEm
Line
Count
Source
218
97.4M
    {
219
97.4M
        if (count > m_bit_count)
220
1.66M
            TRY(refill_buffer_from_stream(count));
221
222
97.4M
        return m_bit_buffer & lsb_mask<T>(min(count, m_bit_count));
223
97.4M
    }
_ZN2AK26LittleEndianInputBitStream9peek_bitsITkNS_8Concepts8UnsignedEtEENS_7ErrorOrIT_NS_5ErrorEEEm
Line
Count
Source
218
20.1M
    {
219
20.1M
        if (count > m_bit_count)
220
1.94M
            TRY(refill_buffer_from_stream(count));
221
222
20.1M
        return m_bit_buffer & lsb_mask<T>(min(count, m_bit_count));
223
20.1M
    }
Unexecuted instantiation: _ZN2AK26LittleEndianInputBitStream9peek_bitsITkNS_8Concepts8UnsignedEhEENS_7ErrorOrIT_NS_5ErrorEEEm
224
225
    ALWAYS_INLINE void discard_previously_peeked_bits(u8 count)
226
1.00G
    {
227
        // We allow "retrieving" more bits than we can provide, but we need to make sure that we don't underflow the current bit counter.
228
        // This only affects certain "modes", but all the relevant checks have been handled in the respective `peek_bits` call.
229
1.00G
        if (count > m_bit_count)
230
0
            count = m_bit_count;
231
232
1.00G
        m_bit_buffer >>= count;
233
1.00G
        m_bit_count -= count;
234
1.00G
    }
235
236
    /// Discards any sub-byte stream positioning the input stream may be keeping track of.
237
    /// Non-bitwise reads will implicitly call this.
238
    u8 align_to_byte_boundary()
239
5.50M
    {
240
5.50M
        u8 remaining_bits = 0;
241
242
5.50M
        if (auto offset = m_bit_count % bits_per_byte; offset != 0) {
243
115k
            remaining_bits = m_bit_buffer & lsb_mask<u8>(offset);
244
115k
            discard_previously_peeked_bits(offset);
245
115k
        }
246
247
5.50M
        return remaining_bits;
248
5.50M
    }
249
250
private:
251
    ErrorOr<void> refill_buffer_from_stream(size_t requested_bit_count)
252
470M
    {
253
485M
        while (requested_bit_count > m_bit_count) [[likely]] {
254
470M
            if (m_stream->is_eof()) [[unlikely]] {
255
454M
                if (m_unsatisfiable_read_behavior == UnsatisfiableReadBehavior::FillWithZero) {
256
454M
                    m_bit_count = requested_bit_count;
257
454M
                    return {};
258
454M
                }
259
260
6.41k
                return Error::from_string_literal("Reached end-of-stream without collecting the required number of bits");
261
454M
            }
262
263
15.5M
            size_t bits_to_read = bit_buffer_size - m_bit_count;
264
15.5M
            size_t bytes_to_read = bits_to_read / bits_per_byte;
265
266
15.5M
            BufferType buffer = 0;
267
15.5M
            auto bytes = TRY(m_stream->read_some({ &buffer, bytes_to_read }));
268
269
15.5M
            m_bit_buffer |= (buffer << m_bit_count);
270
15.5M
            m_bit_count += bytes.size() * bits_per_byte;
271
15.5M
        }
272
273
15.5M
        return {};
274
470M
    }
AK::LittleEndianInputBitStream::refill_buffer_from_stream(unsigned long)
Line
Count
Source
252
470M
    {
253
485M
        while (requested_bit_count > m_bit_count) [[likely]] {
254
470M
            if (m_stream->is_eof()) [[unlikely]] {
255
454M
                if (m_unsatisfiable_read_behavior == UnsatisfiableReadBehavior::FillWithZero) {
256
454M
                    m_bit_count = requested_bit_count;
257
454M
                    return {};
258
454M
                }
259
260
6.41k
                return Error::from_string_literal("Reached end-of-stream without collecting the required number of bits");
261
454M
            }
262
263
15.5M
            size_t bits_to_read = bit_buffer_size - m_bit_count;
264
15.5M
            size_t bytes_to_read = bits_to_read / bits_per_byte;
265
266
15.5M
            BufferType buffer = 0;
267
15.5M
            auto bytes = TRY(m_stream->read_some({ &buffer, bytes_to_read }));
268
269
15.5M
            m_bit_buffer |= (buffer << m_bit_count);
270
15.5M
            m_bit_count += bytes.size() * bits_per_byte;
271
15.5M
        }
272
273
15.5M
        return {};
274
470M
    }
Unexecuted instantiation: AK::LittleEndianInputBitStream::refill_buffer_from_stream(unsigned long)
275
276
    UnsatisfiableReadBehavior m_unsatisfiable_read_behavior;
277
};
278
279
/// A stream wrapper class that allows you to write arbitrary amounts of bits
280
/// in big-endian order to another stream.
281
class BigEndianOutputBitStream : public Stream {
282
public:
283
    explicit BigEndianOutputBitStream(MaybeOwned<Stream> stream)
284
2.12k
        : m_stream(move(stream))
285
2.12k
    {
286
2.12k
    }
287
288
    virtual ErrorOr<Bytes> read_some(Bytes) override
289
0
    {
290
0
        return Error::from_errno(EBADF);
291
0
    }
292
293
    virtual ErrorOr<size_t> write_some(ReadonlyBytes bytes) override
294
0
    {
295
0
        VERIFY(m_bit_offset == 0);
296
0
        return m_stream->write_some(bytes);
297
0
    }
Unexecuted instantiation: AK::BigEndianOutputBitStream::write_some(AK::Span<unsigned char const>)
Unexecuted instantiation: AK::BigEndianOutputBitStream::write_some(AK::Span<unsigned char const>)
298
299
    template<Unsigned T>
300
    ErrorOr<void> write_bits(T value, size_t bit_count)
301
615M
    {
302
615M
        VERIFY(m_bit_offset <= 7);
303
304
1.34G
        while (bit_count > 0) {
305
729M
            u8 next_bit = (value >> (bit_count - 1)) & 1;
306
729M
            bit_count--;
307
308
729M
            m_current_byte <<= 1;
309
729M
            m_current_byte |= next_bit;
310
729M
            m_bit_offset++;
311
312
729M
            if (m_bit_offset > 7) {
313
91.1M
                TRY(m_stream->write_value(m_current_byte));
314
91.1M
                m_bit_offset = 0;
315
91.1M
                m_current_byte = 0;
316
91.1M
            }
317
729M
        }
318
319
615M
        return {};
320
615M
    }
321
322
    virtual bool is_eof() const override
323
0
    {
324
0
        return true;
325
0
    }
326
327
    virtual bool is_open() const override
328
0
    {
329
0
        return m_stream->is_open();
330
0
    }
331
332
    virtual void close() override
333
0
    {
334
0
    }
335
336
    size_t bit_offset() const
337
0
    {
338
0
        return m_bit_offset;
339
0
    }
340
341
    ErrorOr<void> align_to_byte_boundary()
342
360k
    {
343
360k
        if (m_bit_offset == 0)
344
297k
            return {};
345
346
360k
        TRY(write_bits(0u, 8 - m_bit_offset));
347
126k
        VERIFY(m_bit_offset == 0);
348
63.0k
        return {};
349
126k
    }
AK::BigEndianOutputBitStream::align_to_byte_boundary()
Line
Count
Source
342
360k
    {
343
360k
        if (m_bit_offset == 0)
344
297k
            return {};
345
346
360k
        TRY(write_bits(0u, 8 - m_bit_offset));
347
126k
        VERIFY(m_bit_offset == 0);
348
63.0k
        return {};
349
126k
    }
Unexecuted instantiation: AK::BigEndianOutputBitStream::align_to_byte_boundary()
350
351
private:
352
    MaybeOwned<Stream> m_stream;
353
    u8 m_current_byte { 0 };
354
    size_t m_bit_offset { 0 };
355
};
356
357
/// A stream wrapper class that allows you to write arbitrary amounts of bits
358
/// in little-endian order to another stream.
359
class LittleEndianOutputBitStream : public LittleEndianBitStream {
360
public:
361
    explicit LittleEndianOutputBitStream(MaybeOwned<Stream> stream)
362
3.48k
        : LittleEndianBitStream(move(stream))
363
3.48k
    {
364
3.48k
    }
365
366
    virtual ErrorOr<Bytes> read_some(Bytes) override
367
0
    {
368
0
        return Error::from_errno(EBADF);
369
0
    }
370
371
    virtual ErrorOr<size_t> write_some(ReadonlyBytes bytes) override
372
12.4k
    {
373
12.4k
        VERIFY(is_aligned_to_byte_boundary());
374
375
12.4k
        if (m_bit_count > 0)
376
4.10k
            TRY(flush_buffer_to_stream());
377
378
12.4k
        return m_stream->write_some(bytes);
379
12.4k
    }
AK::LittleEndianOutputBitStream::write_some(AK::Span<unsigned char const>)
Line
Count
Source
372
12.4k
    {
373
12.4k
        VERIFY(is_aligned_to_byte_boundary());
374
375
12.4k
        if (m_bit_count > 0)
376
4.10k
            TRY(flush_buffer_to_stream());
377
378
12.4k
        return m_stream->write_some(bytes);
379
12.4k
    }
Unexecuted instantiation: AK::LittleEndianOutputBitStream::write_some(AK::Span<unsigned char const>)
380
381
    template<Unsigned T>
382
    ErrorOr<void> write_bits(T value, size_t count)
383
92.4M
    {
384
92.4M
        if (m_bit_count == bit_buffer_size) {
385
0
            TRY(flush_buffer_to_stream());
386
92.4M
        } else if (auto remaining = bit_buffer_size - m_bit_count; count >= remaining) {
387
9.57M
            m_bit_buffer |= (static_cast<BufferType>(value) & lsb_mask<BufferType>(remaining)) << m_bit_count;
388
9.57M
            m_bit_count = bit_buffer_size;
389
390
9.57M
            if (remaining != sizeof(value) * bits_per_byte)
391
9.57M
                value >>= remaining;
392
9.57M
            count -= remaining;
393
394
9.57M
            TRY(flush_buffer_to_stream());
395
9.57M
        }
396
397
92.4M
        if (count == 0)
398
4.32M
            return {};
399
400
88.1M
        m_bit_buffer |= static_cast<BufferType>(value) << m_bit_count;
401
88.1M
        m_bit_count += count;
402
403
88.1M
        return {};
404
92.4M
    }
_ZN2AK27LittleEndianOutputBitStream10write_bitsITkNS_8Concepts8UnsignedEhEENS_7ErrorOrIvNS_5ErrorEEET_m
Line
Count
Source
383
338k
    {
384
338k
        if (m_bit_count == bit_buffer_size) {
385
0
            TRY(flush_buffer_to_stream());
386
338k
        } else if (auto remaining = bit_buffer_size - m_bit_count; count >= remaining) {
387
15.8k
            m_bit_buffer |= (static_cast<BufferType>(value) & lsb_mask<BufferType>(remaining)) << m_bit_count;
388
15.8k
            m_bit_count = bit_buffer_size;
389
390
15.8k
            if (remaining != sizeof(value) * bits_per_byte)
391
15.8k
                value >>= remaining;
392
15.8k
            count -= remaining;
393
394
15.8k
            TRY(flush_buffer_to_stream());
395
15.8k
        }
396
397
338k
        if (count == 0)
398
5.02k
            return {};
399
400
333k
        m_bit_buffer |= static_cast<BufferType>(value) << m_bit_count;
401
333k
        m_bit_count += count;
402
403
333k
        return {};
404
338k
    }
_ZN2AK27LittleEndianOutputBitStream10write_bitsITkNS_8Concepts8UnsignedEtEENS_7ErrorOrIvNS_5ErrorEEET_m
Line
Count
Source
383
92.0M
    {
384
92.0M
        if (m_bit_count == bit_buffer_size) {
385
0
            TRY(flush_buffer_to_stream());
386
92.0M
        } else if (auto remaining = bit_buffer_size - m_bit_count; count >= remaining) {
387
9.55M
            m_bit_buffer |= (static_cast<BufferType>(value) & lsb_mask<BufferType>(remaining)) << m_bit_count;
388
9.55M
            m_bit_count = bit_buffer_size;
389
390
9.55M
            if (remaining != sizeof(value) * bits_per_byte)
391
9.55M
                value >>= remaining;
392
9.55M
            count -= remaining;
393
394
9.55M
            TRY(flush_buffer_to_stream());
395
9.55M
        }
396
397
92.0M
        if (count == 0)
398
4.32M
            return {};
399
400
87.7M
        m_bit_buffer |= static_cast<BufferType>(value) << m_bit_count;
401
87.7M
        m_bit_count += count;
402
403
87.7M
        return {};
404
92.0M
    }
_ZN2AK27LittleEndianOutputBitStream10write_bitsITkNS_8Concepts8UnsignedEmEENS_7ErrorOrIvNS_5ErrorEEET_m
Line
Count
Source
383
30.5k
    {
384
30.5k
        if (m_bit_count == bit_buffer_size) {
385
0
            TRY(flush_buffer_to_stream());
386
30.5k
        } else if (auto remaining = bit_buffer_size - m_bit_count; count >= remaining) {
387
1.91k
            m_bit_buffer |= (static_cast<BufferType>(value) & lsb_mask<BufferType>(remaining)) << m_bit_count;
388
1.91k
            m_bit_count = bit_buffer_size;
389
390
1.91k
            if (remaining != sizeof(value) * bits_per_byte)
391
1.91k
                value >>= remaining;
392
1.91k
            count -= remaining;
393
394
1.91k
            TRY(flush_buffer_to_stream());
395
1.91k
        }
396
397
30.5k
        if (count == 0)
398
496
            return {};
399
400
30.0k
        m_bit_buffer |= static_cast<BufferType>(value) << m_bit_count;
401
30.0k
        m_bit_count += count;
402
403
30.0k
        return {};
404
30.5k
    }
_ZN2AK27LittleEndianOutputBitStream10write_bitsITkNS_8Concepts8UnsignedEbEENS_7ErrorOrIvNS_5ErrorEEET_m
Line
Count
Source
383
15.6k
    {
384
15.6k
        if (m_bit_count == bit_buffer_size) {
385
0
            TRY(flush_buffer_to_stream());
386
15.6k
        } else if (auto remaining = bit_buffer_size - m_bit_count; count >= remaining) {
387
295
            m_bit_buffer |= (static_cast<BufferType>(value) & lsb_mask<BufferType>(remaining)) << m_bit_count;
388
295
            m_bit_count = bit_buffer_size;
389
390
295
            if (remaining != sizeof(value) * bits_per_byte)
391
295
                value >>= remaining;
392
295
            count -= remaining;
393
394
295
            TRY(flush_buffer_to_stream());
395
295
        }
396
397
15.6k
        if (count == 0)
398
295
            return {};
399
400
15.3k
        m_bit_buffer |= static_cast<BufferType>(value) << m_bit_count;
401
15.3k
        m_bit_count += count;
402
403
15.3k
        return {};
404
15.6k
    }
_ZN2AK27LittleEndianOutputBitStream10write_bitsITkNS_8Concepts8UnsignedEjEENS_7ErrorOrIvNS_5ErrorEEET_m
Line
Count
Source
383
15.7k
    {
384
15.7k
        if (m_bit_count == bit_buffer_size) {
385
0
            TRY(flush_buffer_to_stream());
386
15.7k
        } else if (auto remaining = bit_buffer_size - m_bit_count; count >= remaining) {
387
438
            m_bit_buffer |= (static_cast<BufferType>(value) & lsb_mask<BufferType>(remaining)) << m_bit_count;
388
438
            m_bit_count = bit_buffer_size;
389
390
438
            if (remaining != sizeof(value) * bits_per_byte)
391
438
                value >>= remaining;
392
438
            count -= remaining;
393
394
438
            TRY(flush_buffer_to_stream());
395
438
        }
396
397
15.7k
        if (count == 0)
398
259
            return {};
399
400
15.4k
        m_bit_buffer |= static_cast<BufferType>(value) << m_bit_count;
401
15.4k
        m_bit_count += count;
402
403
15.4k
        return {};
404
15.7k
    }
Unexecuted instantiation: _ZN2AK27LittleEndianOutputBitStream10write_bitsITkNS_8Concepts8UnsignedEhEENS_7ErrorOrIvNS_5ErrorEEET_m
405
406
    ALWAYS_INLINE ErrorOr<void> flush_buffer_to_stream()
407
9.58M
    {
408
9.58M
        auto bytes_to_write = m_bit_count / bits_per_byte;
409
9.58M
        TRY(m_stream->write_until_depleted({ &m_bit_buffer, bytes_to_write }));
410
411
9.58M
        if (m_bit_count == bit_buffer_size) {
412
9.57M
            m_bit_buffer = 0;
413
9.57M
            m_bit_count = 0;
414
9.57M
        } else {
415
7.59k
            auto bits_written = bytes_to_write * bits_per_byte;
416
417
7.59k
            m_bit_buffer >>= bits_written;
418
7.59k
            m_bit_count -= bits_written;
419
7.59k
        }
420
421
9.58M
        return {};
422
9.58M
    }
423
424
    virtual bool is_eof() const override
425
0
    {
426
0
        return true;
427
0
    }
428
429
    virtual bool is_open() const override
430
0
    {
431
0
        return m_stream->is_open();
432
0
    }
433
434
    virtual void close() override
435
0
    {
436
0
    }
437
438
    size_t bit_offset() const
439
15.6k
    {
440
15.6k
        return m_bit_count;
441
15.6k
    }
442
443
    ErrorOr<void> align_to_byte_boundary()
444
7.62k
    {
445
7.62k
        if (auto offset = m_bit_count % bits_per_byte; offset != 0)
446
6.50k
            TRY(write_bits<u8>(0u, bits_per_byte - offset));
447
448
7.62k
        return {};
449
7.62k
    }
450
};
451
452
template<typename T>
453
concept InputBitStream = OneOf<T, BigEndianInputBitStream, LittleEndianInputBitStream>;
454
455
}
456
457
#if USING_AK_GLOBALLY
458
using AK::InputBitStream;
459
#endif