blob: 9e520e9bdce3f58e575c42890341b7ff38440ff7 [file] [edit]
// Copyright (c) Google LLC 2020
//
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.
#include "./bit_reader.h"
#include "../common/platform.h"
namespace brunsli {
void BrunsliBitReaderInit(BrunsliBitReader* br) {
br->num_bits_ = 0;
br->bits_ = 0;
br->num_debt_bytes_ = 0;
br->is_healthy_ = true;
br->is_optimistic_ = false;
}
void BrunsliBitReaderResume(BrunsliBitReader* br, const uint8_t* buffer,
size_t length) {
br->next_ = buffer;
br->end_ = buffer + length;
br->is_optimistic_ = false;
}
/*
Tries to return "debt" if any, and normalize the state.
Normal state means that less than 8 bits are held in bit buffer.
Peeking (BrunsliBitReaderGet) more bits than actually using
(BrunsliBitReaderDrop) could put bit reader into denormal state.
*/
static BRUNSLI_INLINE void BrunsliBitReaderUnload(BrunsliBitReader* br) {
// Cancel the overdraft.
while ((br->num_debt_bytes_ > 0) && (br->num_bits_ >= 8)) {
br->num_debt_bytes_--;
br->num_bits_ -= 8;
}
// Return unused bytes.
while (br->num_bits_ >= 8) {
br->next_--;
br->num_bits_ -= 8;
}
br->bits_ &= BrunsliBitReaderBitMask(br->num_bits_);
}
size_t BrunsliBitReaderSuspend(BrunsliBitReader* br) {
BrunsliBitReaderUnload(br);
size_t unused_bytes = br->end_ - br->next_;
br->next_ = nullptr;
br->end_ = nullptr;
return unused_bytes;
}
void BrunsliBitReaderFinish(BrunsliBitReader* br) {
uint32_t n_bits = br->num_bits_;
// Likely, did not invoke Suspend before.
if (n_bits >= 8) {
br->is_healthy_ = false;
return;
}
if (n_bits > 0) {
uint32_t padding_bits = BrunsliBitReaderRead(br, n_bits);
if (padding_bits != 0) br->is_healthy_ = false;
}
}
bool BrunsliBitReaderIsHealthy(BrunsliBitReader* br) {
BrunsliBitReaderUnload(br);
return (br->num_debt_bytes_ == 0) && (br->is_healthy_);
}
void BrunsliBitReaderSetOptimistic(BrunsliBitReader* br) {
br->is_optimistic_ = true;
}
bool BrunsliBitReaderCanRead(BrunsliBitReader* br, size_t n_bits) {
if (br->is_optimistic_) return true;
if (br->num_debt_bytes_ != 0) return false;
if (br->num_bits_ >= n_bits) return true;
size_t num_extra_bytes = (n_bits - br->num_bits_ + 7) >> 3;
return (br->next_ + num_extra_bytes <= br->end_);
}
} // namespace brunsli