/src/brunsli/c/dec/brunsli_input.h
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright (c) Google LLC 2019 |
2 | | // |
3 | | // Use of this source code is governed by an MIT-style |
4 | | // license that can be found in the LICENSE file or at |
5 | | // https://opensource.org/licenses/MIT. |
6 | | |
7 | | #ifndef BRUNSLI_DEC_BRUNSLI_INPUT_H_ |
8 | | #define BRUNSLI_DEC_BRUNSLI_INPUT_H_ |
9 | | |
10 | | #include "../common/platform.h" |
11 | | #include <brunsli/types.h> |
12 | | |
13 | | namespace brunsli { |
14 | | |
15 | | static const int kBitMask[] = {0, 1, 3, 7, 15, 31, |
16 | | 63, 127, 255, 511, 1023, 2047, |
17 | | 4095, 8191, 16383, 32767, 65535}; |
18 | | |
19 | | struct WordSource { |
20 | | WordSource(const uint8_t* data, size_t len, bool optimistic) |
21 | 10.9k | : data_(data), |
22 | 10.9k | len_(len & ~1), |
23 | 10.9k | pos_(0), |
24 | 10.9k | error_(false), |
25 | 10.9k | optimistic_(optimistic) {} |
26 | | |
27 | 3.77M | uint16_t GetNextWord() { |
28 | 3.77M | uint16_t val = 0; |
29 | 3.77M | if (pos_ < len_) { /* NB: both pos_ and len_ are even. */ |
30 | 3.74M | val = BRUNSLI_UNALIGNED_LOAD16LE(data_ + pos_); |
31 | 3.74M | } else { |
32 | 32.4k | error_ = true; |
33 | 32.4k | } |
34 | | // TODO(eustas): take care of overflows? |
35 | 3.77M | pos_ += 2; |
36 | 3.77M | return val; |
37 | 3.77M | } |
38 | | |
39 | 40.2M | bool CanRead(size_t n) { |
40 | 40.2M | if (optimistic_) return true; |
41 | 16.8M | size_t delta = 2 * n; |
42 | 16.8M | size_t projected_end = pos_ + delta; |
43 | | // Check for overflow; just in case. |
44 | 16.8M | if (projected_end < pos_) return false; |
45 | 16.8M | return projected_end <= len_; |
46 | 16.8M | } |
47 | | |
48 | | const uint8_t* data_; |
49 | | size_t len_; |
50 | | size_t pos_; |
51 | | bool error_; |
52 | | bool optimistic_; |
53 | | }; |
54 | | |
55 | | struct BitSource { |
56 | 21.3k | BitSource() {} |
57 | | |
58 | 10.7k | void Init(WordSource* in) { |
59 | 10.7k | val_ = in->GetNextWord(); |
60 | 10.7k | bit_pos_ = 0; |
61 | 10.7k | } |
62 | | |
63 | 3.73M | uint32_t ReadBits(int nbits, WordSource* in) { |
64 | 3.73M | if (bit_pos_ + nbits > 16) { |
65 | 1.55M | uint32_t new_bits = in->GetNextWord(); |
66 | 1.55M | val_ |= new_bits << 16; |
67 | 1.55M | } |
68 | 3.73M | uint32_t result = (val_ >> bit_pos_) & kBitMask[nbits]; |
69 | 3.73M | bit_pos_ += nbits; |
70 | 3.73M | if (bit_pos_ > 16) { |
71 | 1.55M | bit_pos_ -= 16; |
72 | 1.55M | val_ >>= 16; |
73 | 1.55M | } |
74 | 3.73M | return result; |
75 | 3.73M | } |
76 | | |
77 | 9.65k | bool Finish() { |
78 | 9.65k | size_t n_bits = 16 - bit_pos_; |
79 | 9.65k | if (n_bits > 0) { |
80 | 8.37k | int padding_bits = (val_ >> bit_pos_) & kBitMask[n_bits]; |
81 | 8.37k | if (padding_bits != 0) return false; |
82 | 8.37k | } |
83 | 9.62k | return true; |
84 | 9.65k | } |
85 | | |
86 | | uint32_t val_; |
87 | | int bit_pos_; |
88 | | }; |
89 | | |
90 | | } // namespace brunsli |
91 | | |
92 | | #endif // BRUNSLI_DEC_BRUNSLI_INPUT_H_ |