Files
easy7zip/C/fast-lzma2/range_enc.h
2018-11-05 21:22:10 +10:00

157 lines
3.7 KiB
C

/*
* Bitwise range encoder by Igor Pavlov
* Modified by Conor McCarthy
*
* Public domain
*/
#ifndef RANGE_ENCODER_H
#define RANGE_ENCODER_H
#include "mem.h"
#include "compiler.h"
#if defined (__cplusplus)
extern "C" {
#endif
#ifdef LZMA_ENC_PROB32
typedef U32 Probability;
#else
typedef U16 Probability;
#endif
#define kNumTopBits 24U
#define kTopValue (1UL << kNumTopBits)
#define kNumBitModelTotalBits 11U
#define kBitModelTotal (1 << kNumBitModelTotalBits)
#define kNumMoveBits 5U
#define kProbInitValue (kBitModelTotal >> 1U)
#define kNumMoveReducingBits 4U
#define kNumBitPriceShiftBits 4U
extern const unsigned price_table[kBitModelTotal >> kNumMoveReducingBits];
typedef struct
{
BYTE *out_buffer;
size_t out_index;
size_t chunk_size;
U64 cache_size;
U64 low;
U32 range;
BYTE cache;
} RangeEncoder;
void RangeEncReset(RangeEncoder* const rc);
void SetOutputBuffer(RangeEncoder* const rc, BYTE *const out_buffer, size_t chunk_size);
void RangeEncReset(RangeEncoder* const rc);
void ShiftLow(RangeEncoder* const rc);
void EncodeBitTree(RangeEncoder* const rc, Probability *const probs, unsigned bit_count, unsigned symbol);
void EncodeBitTreeReverse(RangeEncoder* const rc, Probability *const probs, unsigned bit_count, unsigned symbol);
void EncodeDirect(RangeEncoder* const rc, unsigned value, unsigned bit_count);
HINT_INLINE
void EncodeBit0(RangeEncoder* const rc, Probability *const rprob)
{
unsigned prob = *rprob;
rc->range = (rc->range >> kNumBitModelTotalBits) * prob;
prob += (kBitModelTotal - prob) >> kNumMoveBits;
*rprob = (Probability)prob;
if (rc->range < kTopValue) {
rc->range <<= 8;
ShiftLow(rc);
}
}
HINT_INLINE
void EncodeBit1(RangeEncoder* const rc, Probability *const rprob)
{
unsigned prob = *rprob;
U32 new_bound = (rc->range >> kNumBitModelTotalBits) * prob;
rc->low += new_bound;
rc->range -= new_bound;
prob -= prob >> kNumMoveBits;
*rprob = (Probability)prob;
if (rc->range < kTopValue) {
rc->range <<= 8;
ShiftLow(rc);
}
}
HINT_INLINE
void EncodeBit(RangeEncoder* const rc, Probability *const rprob, unsigned const bit)
{
unsigned prob = *rprob;
if (bit != 0) {
U32 new_bound = (rc->range >> kNumBitModelTotalBits) * prob;
rc->low += new_bound;
rc->range -= new_bound;
prob -= prob >> kNumMoveBits;
}
else {
rc->range = (rc->range >> kNumBitModelTotalBits) * prob;
prob += (kBitModelTotal - prob) >> kNumMoveBits;
}
*rprob = (Probability)prob;
if (rc->range < kTopValue) {
rc->range <<= 8;
ShiftLow(rc);
}
}
#define GET_PRICE(rc, prob, symbol) \
price_table[((prob) ^ ((-(int)(symbol)) & (kBitModelTotal - 1))) >> kNumMoveReducingBits];
#define GET_PRICE_0(rc, prob) price_table[(prob) >> kNumMoveReducingBits]
#define GET_PRICE_1(rc, prob) price_table[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits]
HINT_INLINE
unsigned GetTreePrice(RangeEncoder* const rc, const Probability* const prob_table, unsigned const bit_count, size_t symbol)
{
unsigned price = 0;
symbol |= ((size_t)1 << bit_count);
while (symbol != 1) {
size_t next_symbol = symbol >> 1;
unsigned prob = prob_table[next_symbol];
unsigned bit = (unsigned)symbol & 1;
price += GET_PRICE(rc, prob, bit);
symbol = next_symbol;
}
return price;
}
HINT_INLINE
unsigned GetReverseTreePrice(RangeEncoder* const rc, const Probability* const prob_table, unsigned const bit_count, size_t symbol)
{
unsigned price = 0;
size_t m = 1;
for (unsigned i = bit_count; i != 0; --i) {
unsigned prob = prob_table[m];
unsigned bit = symbol & 1;
symbol >>= 1;
price += GET_PRICE(rc, prob, bit);
m = (m << 1) | bit;
}
return price;
}
HINT_INLINE
void Flush(RangeEncoder* const rc)
{
for (int i = 0; i < 5; ++i)
ShiftLow(rc);
}
#if defined (__cplusplus)
}
#endif
#endif /* RANGE_ENCODER_H */