/src/brunsli/c/dec/brunsli_input.h
Line | Count | Source |
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 <brunsli/types.h> |
11 | | |
12 | | #include "../common/platform.h" |
13 | | |
14 | | namespace brunsli { |
15 | | |
16 | | static const int kBitMask[] = {0, 1, 3, 7, 15, 31, |
17 | | 63, 127, 255, 511, 1023, 2047, |
18 | | 4095, 8191, 16383, 32767, 65535}; |
19 | | |
20 | | struct WordSource { |
21 | | WordSource(const uint8_t* data, size_t len, bool optimistic) |
22 | 278k | : data_(data), |
23 | 278k | len_(len & ~1), |
24 | 278k | pos_(0), |
25 | 278k | error_(false), |
26 | 278k | optimistic_(optimistic) {} |
27 | | |
28 | 2.60M | uint16_t GetNextWord() { |
29 | 2.60M | uint16_t val = 0; |
30 | 2.60M | if (pos_ < len_) { /* NB: both pos_ and len_ are even. */ |
31 | 2.55M | val = BRUNSLI_UNALIGNED_LOAD16LE(data_ + pos_); |
32 | 2.55M | } else { |
33 | 41.1k | error_ = true; |
34 | 41.1k | } |
35 | | // TODO(eustas): take care of overflows? |
36 | 2.60M | pos_ += 2; |
37 | 2.60M | return val; |
38 | 2.60M | } |
39 | | |
40 | 59.4M | bool CanRead(size_t n) { |
41 | 59.4M | if (optimistic_) return true; |
42 | 24.0M | size_t delta = 2 * n; |
43 | 24.0M | size_t projected_end = pos_ + delta; |
44 | | // Check for overflow; just in case. |
45 | 24.0M | if (projected_end < pos_) return false; |
46 | 24.0M | return projected_end <= len_; |
47 | 24.0M | } |
48 | | |
49 | | const uint8_t* data_; |
50 | | size_t len_; |
51 | | size_t pos_; |
52 | | bool error_; |
53 | | bool optimistic_; |
54 | | }; |
55 | | |
56 | | struct BitSource { |
57 | 39.9k | BitSource() {} |
58 | | |
59 | 20.2k | void Init(WordSource* in) { |
60 | 20.2k | val_ = in->GetNextWord(); |
61 | 20.2k | bit_pos_ = 0; |
62 | 20.2k | } |
63 | | |
64 | 2.90M | uint32_t ReadBits(int nbits, WordSource* in) { |
65 | 2.90M | if (bit_pos_ + nbits > 16) { |
66 | 742k | uint32_t new_bits = in->GetNextWord(); |
67 | 742k | val_ |= new_bits << 16; |
68 | 742k | } |
69 | 2.90M | uint32_t result = (val_ >> bit_pos_) & kBitMask[nbits]; |
70 | 2.90M | bit_pos_ += nbits; |
71 | 2.90M | if (bit_pos_ > 16) { |
72 | 742k | bit_pos_ -= 16; |
73 | 742k | val_ >>= 16; |
74 | 742k | } |
75 | 2.90M | return result; |
76 | 2.90M | } |
77 | | |
78 | 18.1k | bool Finish() { |
79 | 18.1k | size_t n_bits = 16 - bit_pos_; |
80 | 18.1k | if (n_bits > 0) { |
81 | 15.5k | int padding_bits = (val_ >> bit_pos_) & kBitMask[n_bits]; |
82 | 15.5k | if (padding_bits != 0) return false; |
83 | 15.5k | } |
84 | 18.0k | return true; |
85 | 18.1k | } |
86 | | |
87 | | uint32_t val_; |
88 | | int bit_pos_; |
89 | | }; |
90 | | |
91 | | } // namespace brunsli |
92 | | |
93 | | #endif // BRUNSLI_DEC_BRUNSLI_INPUT_H_ |