/src/brunsli/c/dec/bit_reader.cc
Line | Count | Source |
1 | | // Copyright (c) Google LLC 2020 |
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 | | #include "./bit_reader.h" |
8 | | |
9 | | #include "../common/platform.h" |
10 | | |
11 | | namespace brunsli { |
12 | | |
13 | 23.5k | void BrunsliBitReaderInit(BrunsliBitReader* br) { |
14 | 23.5k | br->num_bits_ = 0; |
15 | 23.5k | br->bits_ = 0; |
16 | 23.5k | br->num_debt_bytes_ = 0; |
17 | 23.5k | br->is_healthy_ = true; |
18 | 23.5k | br->is_optimistic_ = false; |
19 | 23.5k | } |
20 | | |
21 | | void BrunsliBitReaderResume(BrunsliBitReader* br, const uint8_t* buffer, |
22 | 23.5k | size_t length) { |
23 | 23.5k | br->next_ = buffer; |
24 | 23.5k | br->end_ = buffer + length; |
25 | 23.5k | br->is_optimistic_ = false; |
26 | 23.5k | } |
27 | | |
28 | | /* |
29 | | Tries to return "debt" if any, and normalize the state. |
30 | | |
31 | | Normal state means that less than 8 bits are held in bit buffer. |
32 | | Peeking (BrunsliBitReaderGet) more bits than actually using |
33 | | (BrunsliBitReaderDrop) could put bit reader into denormal state. |
34 | | */ |
35 | 67.2k | static BRUNSLI_INLINE void BrunsliBitReaderUnload(BrunsliBitReader* br) { |
36 | | // Cancel the overdraft. |
37 | 67.3k | while ((br->num_debt_bytes_ > 0) && (br->num_bits_ >= 8)) { |
38 | 110 | br->num_debt_bytes_--; |
39 | 110 | br->num_bits_ -= 8; |
40 | 110 | } |
41 | | // Return unused bytes. |
42 | 67.7k | while (br->num_bits_ >= 8) { |
43 | 571 | br->next_--; |
44 | 571 | br->num_bits_ -= 8; |
45 | 571 | } |
46 | 67.2k | br->bits_ &= BrunsliBitReaderBitMask(br->num_bits_); |
47 | 67.2k | } |
48 | | |
49 | 23.5k | size_t BrunsliBitReaderSuspend(BrunsliBitReader* br) { |
50 | 23.5k | BrunsliBitReaderUnload(br); |
51 | 23.5k | size_t unused_bytes = br->end_ - br->next_; |
52 | 23.5k | br->next_ = nullptr; |
53 | 23.5k | br->end_ = nullptr; |
54 | 23.5k | return unused_bytes; |
55 | 23.5k | } |
56 | | |
57 | 19.0k | void BrunsliBitReaderFinish(BrunsliBitReader* br) { |
58 | 19.0k | uint32_t n_bits = br->num_bits_; |
59 | | // Likely, did not invoke Suspend before. |
60 | 19.0k | if (n_bits >= 8) { |
61 | 0 | br->is_healthy_ = false; |
62 | 0 | return; |
63 | 0 | } |
64 | 19.0k | if (n_bits > 0) { |
65 | 13.5k | uint32_t padding_bits = BrunsliBitReaderRead(br, n_bits); |
66 | 13.5k | if (padding_bits != 0) br->is_healthy_ = false; |
67 | 13.5k | } |
68 | 19.0k | } |
69 | | |
70 | 43.6k | bool BrunsliBitReaderIsHealthy(BrunsliBitReader* br) { |
71 | 43.6k | BrunsliBitReaderUnload(br); |
72 | 43.6k | return (br->num_debt_bytes_ == 0) && (br->is_healthy_); |
73 | 43.6k | } |
74 | | |
75 | 5.63k | void BrunsliBitReaderSetOptimistic(BrunsliBitReader* br) { |
76 | 5.63k | br->is_optimistic_ = true; |
77 | 5.63k | } |
78 | | |
79 | 3.83M | bool BrunsliBitReaderCanRead(BrunsliBitReader* br, size_t n_bits) { |
80 | 3.83M | if (br->is_optimistic_) return true; |
81 | 2.85M | if (br->num_debt_bytes_ != 0) return false; |
82 | 2.85M | if (br->num_bits_ >= n_bits) return true; |
83 | 1.63M | size_t num_extra_bytes = (n_bits - br->num_bits_ + 7) >> 3; |
84 | 1.63M | return (br->next_ + num_extra_bytes <= br->end_); |
85 | 2.85M | } |
86 | | |
87 | | } // namespace brunsli |