#ifndef __LC3_BITS_H
#define __LC3_BITS_H
#include "common.h"
enum lc3_bits_mode {
LC3_BITS_MODE_READ,
LC3_BITS_MODE_WRITE,
};
struct lc3_ac_symbol {
uint16_t low : 16;
uint16_t range : 16;
};
struct lc3_ac_model {
struct lc3_ac_symbol s[17];
};
#define LC3_ACCU_BITS (int)(8 * sizeof(unsigned))
struct lc3_bits_accu {
unsigned v;
int n, nover;
};
#define LC3_AC_BITS (int)(24)
struct lc3_bits_ac {
unsigned low, range;
int cache, carry, carry_count;
bool error;
};
struct lc3_bits_buffer {
const uint8_t *start, *end;
uint8_t *p_fw, *p_bw;
};
typedef struct lc3_bits {
enum lc3_bits_mode mode;
struct lc3_bits_ac ac;
struct lc3_bits_accu accu;
struct lc3_bits_buffer buffer;
} lc3_bits_t;
void lc3_setup_bits(lc3_bits_t *bits,
enum lc3_bits_mode mode, void *buffer, int len);
int lc3_get_bits_left(const lc3_bits_t *bits);
int lc3_check_bits(const lc3_bits_t *bits);
static inline void lc3_put_bit(lc3_bits_t *bits, int v);
static inline void lc3_put_bits(lc3_bits_t *bits, unsigned v, int n);
static inline void lc3_put_symbol(lc3_bits_t *bits,
const struct lc3_ac_model *model, unsigned s);
void lc3_flush_bits(lc3_bits_t *bits);
static inline int lc3_get_bit(lc3_bits_t *bits);
static inline unsigned lc3_get_bits(lc3_bits_t *bits, int n);
static inline unsigned lc3_get_symbol(lc3_bits_t *bits,
const struct lc3_ac_model *model);
void lc3_put_bits_generic(lc3_bits_t *bits, unsigned v, int n);
unsigned lc3_get_bits_generic(struct lc3_bits *bits, int n);
void lc3_ac_read_renorm(lc3_bits_t *bits);
void lc3_ac_write_renorm(lc3_bits_t *bits);
LC3_HOT static inline void lc3_put_bit(lc3_bits_t *bits, int v)
{
lc3_put_bits(bits, v, 1);
}
LC3_HOT static inline void lc3_put_bits(
struct lc3_bits *bits, unsigned v, int n)
{
struct lc3_bits_accu *accu = &bits->accu;
if (accu->n + n <= LC3_ACCU_BITS) {
accu->v |= v << accu->n;
accu->n += n;
} else {
lc3_put_bits_generic(bits, v, n);
}
}
LC3_HOT static inline int lc3_get_bit(lc3_bits_t *bits)
{
return lc3_get_bits(bits, 1);
}
LC3_HOT static inline unsigned lc3_get_bits(struct lc3_bits *bits, int n)
{
struct lc3_bits_accu *accu = &bits->accu;
if (accu->n + n <= LC3_ACCU_BITS) {
int v = (accu->v >> accu->n) & ((1u << n) - 1);
return (accu->n += n), v;
}
else {
return lc3_get_bits_generic(bits, n);
}
}
LC3_HOT static inline void lc3_put_symbol(
struct lc3_bits *bits, const struct lc3_ac_model *model, unsigned s)
{
const struct lc3_ac_symbol *symbols = model->s;
struct lc3_bits_ac *ac = &bits->ac;
unsigned range = ac->range >> 10;
ac->low += range * symbols[s].low;
ac->range = range * symbols[s].range;
ac->carry |= ac->low >> 24;
ac->low &= 0xffffff;
if (ac->range < 0x10000)
lc3_ac_write_renorm(bits);
}
LC3_HOT static inline unsigned lc3_get_symbol(
lc3_bits_t *bits, const struct lc3_ac_model *model)
{
const struct lc3_ac_symbol *symbols = model->s;
struct lc3_bits_ac *ac = &bits->ac;
unsigned range = (ac->range >> 10) & 0xffff;
ac->error |= (ac->low >= (range << 10));
if (ac->error)
ac->low = 0;
int s = 16;
if (ac->low < range * symbols[s].low) {
s >>= 1;
s -= ac->low < range * symbols[s].low ? 4 : -4;
s -= ac->low < range * symbols[s].low ? 2 : -2;
s -= ac->low < range * symbols[s].low ? 1 : -1;
s -= ac->low < range * symbols[s].low;
}
ac->low -= range * symbols[s].low;
ac->range = range * symbols[s].range;
if (ac->range < 0x10000)
lc3_ac_read_renorm(bits);
return s;
}
#endif